How do you invert Map<v1, Set<v2>> to Map<v2, Set<v1>> in Java with stream()

人盡茶涼 提交于 2020-01-01 19:11:47

问题


I have a Map object Map<t1, Set<t2>>, and I want to go into the set and turn t2 in the sets into the keys of the new map. The original key t1 will be the new value of the map.
For example, given a map containing two entries

{key1: [a, b, c], key2: [c, d]}

The resulting map would be

{a: [key1], b: [key1], c: [key1, key2], d: [key2]}

[ ] denotes Set in the above examples.


回答1:


Java 8:

map.entrySet()
        .stream()
        .flatMap(e -> e.getValue()
                .stream()
                .map(v -> new SimpleEntry<>(v, e.getKey())))
        .collect(Collectors.groupingBy(Entry::getKey,
                Collectors.mapping(Entry::getValue, Collectors.toSet())))

Guava:

Multimaps.asMap(map.entrySet()
        .stream()
        .collect(ImmutableSetMultimap.flatteningToImmutableSetMultimap(
                Entry::getKey, e -> e.getValue().stream()))
        .inverse())

StreamEx:

EntryStream.of(map)
        .flatMapValues(Set::stream)
        .invert()
        .grouping(Collectors.toSet())



回答2:


One way could be :

private static <T1,T2> Map<T1, Set<T2>> invertMap(Map<T2, Set<T1>> data) {
        Map<T1, Set<T2>> output = data.entrySet().stream().collect(() -> new HashMap<T1, Set<T2>>(),
                (mapLeft, leftEntry) -> {
                    for (T1 i : leftEntry.getValue()) {

                        Set<T2> values = mapLeft.get(i);
                        if (values == null)
                            values = new HashSet<>();

                        values.add(leftEntry.getKey());
                        mapLeft.put(i, values);
                    }
                }, (mapLeft, mapRight) -> mapLeft.putAll(mapRight));
        return output;
    }



回答3:


One way to do it could be -

Map<V1,Set<V2>> inputHashMap = new HashMap<>(); // initialized with your input
Map<V2,Set<V1>> outputHashMap = new HashMap<>();

inputHashMap.forEach((val, keys) -> keys.forEach(key -> {
    if (outputHashMap.containsKey(key)) {
        outputHashMap.get(key).add(val);
    } else {
        outputHashMap.put(key, new HashSet<>() {{
            add(val);
        }});
    }
}));



回答4:


Using stream (might be good for parallel processing using parallel() on stream)

Map<String, Set<String>> inMap = new HashMap<>();
inMap.put("key1", new HashSet<>(Arrays.asList("a", "b", "c")));
inMap.put("key2", new HashSet<>(Arrays.asList("c", "d")));

Map<String, Set<String>> outMap = inMap.entrySet().stream().collect(
    HashMap::new,
    (m, e) -> e.getValue().forEach(v -> m.computeIfAbsent(v, ignore -> new HashSet<>())
                                         .add(e.getKey())),
    (m1, m2) -> m2.forEach((key, value) -> m1.merge(key, value,
                                           (s1, s2) -> { s1.addAll(s2); return s1; })));

System.out.println(outMap);
// {a=[key1], b=[key1], c=[key1, key2], d=[key2]}

Of course old school for loop is much more cleaner

Map<String, Set<String>> outMap = new HashMap<>();

for (Entry<String, Set<String>> e : inMap.entrySet())
  for (String v : e.getValue())
    outMap.computeIfAbsent(v, key -> new HashSet<>()).add(e.getKey());

Less LOC

Map<String, Set<String>> outMap = new HashMap<>();
inMap.forEach((k, v) -> v.forEach(e ->
  outMap.computeIfAbsent(e, __ -> new HashSet<>()).add(k)));


来源:https://stackoverflow.com/questions/46480725/how-do-you-invert-mapv1-setv2-to-mapv2-setv1-in-java-with-stream

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!