如何创建Map <T,List <K >> out of Map <K,List <T >>?

Mak*_*ski 6 java hashmap java-8 java-stream

我正在尝试实现该功能:

private static <T, K> Map<T, List<K> > invertedMap(Map<K, List<T> > m)
Run Code Online (Sandbox Code Playgroud)

例如,如果我有Map<String, List<Integer> >,

我想创造另一个Map<Integer, List<String> >.

我写了一些代码:

private static <T, K> Map<T, List<K>> invertedMap(Map<K, T> m) {
    return m.keySet().stream()
            .collect(Collectors.groupingBy(k -> m.get(k)));
}
Run Code Online (Sandbox Code Playgroud)

但正如您所看到的,只有在参数中的地图不包含列表作为值时,这才有效.

Fed*_*ner 8

我不会为此使用流(如果你想要一个基于流的解决方案,请检查 nullpointer的答案):

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;
}
Run Code Online (Sandbox Code Playgroud)

上面的代码迭代输入映射map和每个元件t其中的每一个的List值l,它使用Map.computeIfAbsent以生成结果.

Map.computeIfAbsent如果有给定键的条目,则返回该值,或者创建该条目并返回其第二个参数指定的值d -> new ArrayList<>()(这里d代表我们不需要的伪参数,以便创建新的空列表).然后,将密钥k添加到返回的列表中Map.computeIfAbsent.


Nam*_*man 7

这是一种流式的方式(虽然我的第一直觉本身就是遵循Federico的解决方案):

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())));
}
Run Code Online (Sandbox Code Playgroud)