How to create Map<T, List<K>> out of Map<K, List<T> >?
I wouldn't use streams for this (if you want a stream-based solution, check nullpointer's answer):
private static <T, K> Map<T, List<K>> invertedMap(Map<K, List<T>> map) {
Map<T, List<K>> result = new LinkedHashMap<>(); // Preserves insertion order
map.forEach((k, l) ->
l.forEach(t -> result.computeIfAbsent(t, d -> new ArrayList<>()).add(k)));
return result;
}
The above code iterates the input map map
and for each element t
of each one of its List
values l
, it uses Map.computeIfAbsent
to create the result.
Map.computeIfAbsent
returns the value if there's an entry for the given key, or creates the entry and returns the value specified by its second argument d -> new ArrayList<>()
(here d
stands for a dummy argument that we don't need in order to create a new, empty list). Then, the key k
is added to the list returned by Map.computeIfAbsent
.
Here is a stream way of doing it (though my first instinct itself would be to follow Federico's solution) :
private static <T, K> Map<T, List<K>> invertedMapOfList(Map<K, List<T>> m) {
return m.entrySet()
.stream()
.flatMap(e -> e.getValue()
.stream()
.map(v -> new AbstractMap.SimpleEntry<>(e.getKey(), v)))
.collect(Collectors.groupingBy(Map.Entry::getValue,
Collectors.mapping(Map.Entry::getKey, Collectors.toList())));
}
Hope this will solve your problem.
private static <T, K> Map<T, List<K>> invertedMap(Map<K, List<T>> m) {
Map<T, List<K>> result = new HashMap<T, List<K>>();
for (K key : m.keySet()) {
for (T value : m.get(key)) {
List<K> kList = null;
if ((kList = result.get(value)) == null) {
kList = new ArrayList<K>();
}
kList.add(key);
result.put(value, kList);
}
}
return result;
}