Is there a more elegant/built-in way to reverse the keys and values of a Hashmap?
I currently have the following.
private Map
Guava's BiMap already provides a method for reversing its key-value pairs. Perhaps you could change the interface of the Map
in question to BiMap
, or else use the following code:
private BiMap<Boolean, String> reverseMap(Map<String, Boolean> permissions) {
BiMap<String, Boolean> bimap = HashBiMap.create(permissions);
return bimap.inverse();
}
You might consider using one of Guava's Multimap implementations. For example:
private Multimap<Boolean, String> reverseMap(Map<String, Boolean> permissions) {
Multimap<Boolean, String> multimap = ArrayListMultimap.create();
for (Map.Entry<String, Boolean> entry : permissions.entrySet()) {
multimap.put(entry.getValue(), entry.getKey());
}
return multimap;
}
Or more generally:
private static <K, V> Multimap<V, K> reverseMap(Map<K, V> source) {
Multimap<V, K> multimap = ArrayListMultimap.create();
for (Map.Entry<K, V> entry : source.entrySet()) {
multimap.put(entry.getValue(), entry.getKey());
}
return multimap;
}
I'd do something similar (but if you must do this kind of thing frequently, consider Guava), only replacing the List with Set (seems a little more consistent) and prefilling the reversemap:
private Map<Boolean, Set<String>> reverseMap(Map<String, Boolean> permissions) {
Map<Boolean, Set<String>> returnvalue = new HashMap<Boolean, Set<String>>();
returnvalue.put(Boolean.TRUE, new HashSet<String>());
returnvalue.put(Boolean.FALSE, new HashSet<String>());
for (Entry<String, Boolean> entry : permissions.entrySet())
returnvalue.get(entry.getValue()).add(entry.getKey());
return returnvalue;
}
First thing to note is that you don't really need a reverse map if your values are only true or false. It will make sense if you have a broader range of values.
One easy (but not very elegant) way to get the entries with a specific value is:
public static <T, E> Set<T> getKeysByValue(Map<T, E> map, E value) {
Set<T> keys = new HashSet<T>();
for (Entry<T, E> entry : map.entrySet()) {
if (entry.getValue().equals(value)) {
keys.add(entry.getKey());
}
}
return keys;
}
You can see that this is not so good if you need to call it every now and then. It makes sense to have two different maps (straight and reverse) and add entries to both. You can't use Bidi maps since there is no 1:1 relation between keys and values.
UPDATE: The following solution won't work. See comments.
You can also consider using a TreeMap and keep it sorted based on the value. This way you can have a sorted set by calling map.entrySet()
any time (denies entries first, then allows). The drawback is that it is only one set.
ValueComparator bvc = new ValueComparator(map);
TreeMap<String,Boolean> sorted_map = new TreeMap(bvc);
class ValueComparator implements Comparator {
Map base;
public ValueComparator(Map base) {
this.base = base;
}
public int compare(Object a, Object b) {
return (Boolean)base.get(a).compareTo((Boolean)base.get(b));
}
}