Reputation: 1070
How can we do that with Guava? Notice the presence of List<K>
in the return type since many keys can map to the same value in any normal map.
public static <K, V> Map<V, List<K>> inverse(Map<K, V> map){
Map<V, List<K>> result = new LinkedHashMap<V, List<K>>();
for (Map.Entry<K, V> entry : map.entrySet()) {
if(!result.containsKey(entry.getValue())){
result.put(entry.getValue(), new ArrayList<K>());
}
result.get(entry.getValue()).add(entry.getKey());
}
return result;
}
BiMap
seems to insist on the unicity of the values, but I don't have this luxury.
Upvotes: 19
Views: 12762
Reputation: 4496
In case someone stumbles here now (well within Java's Stream
era), here are two single-expression Stream
-based solutions:
1) Immutable version based on ImmutableListMultimap
+ toImmutableListMultimap
collector
ImmutableListMultimap<V, K> output = inputMap.entrySet().stream()
.collect(ImmutableListMultimap.toImmutableListMultimap(Map.Entry::getValue, Map.Entry::getKey));
2) Mutable version based on ArrayListMultimap
+ Multimaps.toMultimap
collector
ListMultimap<V, K> output = inputMap.entrySet().stream()
.collect(Multimaps.toMultimap(Map.Entry::getValue, Map.Entry::getKey, ArrayListMultimap::create));
Upvotes: 1
Reputation: 96454
Use a Multimap instead, pick one that uses a list, like ArrayListMultimap, that will allow dupes.
Also you don't have to write your own invert method, there's one provided in com.google.common.collect.Multimaps.
Upvotes: 7
Reputation: 110104
You can do this:
Map<K, V> map = ...;
ListMultimap<V, K> inverse = Multimaps.invertFrom(Multimaps.forMap(map),
ArrayListMultimap.<V,K>create());
Do note that pretty much any time you write Map<K, List<V>>
or Map<K, Set<V>>
or some such, a ListMultimap<K, V>
or SetMultimap<K, V>
is what you really want.
Upvotes: 36