将Java 8中的Map<K, List<V>>转换为Map<V, List<K>>

9

我需要将 Map<K, List<V>> 转换为 Map<V, List<K>>

Map<K, V> 转换为 Map<V, List<K>> 很容易实现:

.collect(Collectors.groupingBy(
     Map.Entry::getKey, 
     Collectors.mapping(Map.Entry::getValue, toList())
)

但我无法解决一个最初的问题。有没有一种易于理解的Java 8方法来解决它?

1个回答

13

我认为你很接近了,需要将这些条目flatMap到一个Stream中并从那里收集。我已经使用了已经存在的SimpleEntry,但你也可以使用某种类型的Pair

initialMap.entrySet()
          .stream()
          .flatMap(entry -> entry.getValue().stream().map(v -> new SimpleEntry<>(entry.getKey(), v)))
          .collect(Collectors.groupingBy(
               Entry::getValue,
               Collectors.mapping(Entry::getKey, Collectors.toList())
         ));

如果您不想创建这些SimpleEntry实例的额外开销,可以稍微改变一下做法:

    Map<Integer, List<String>> result = new HashMap<>();

    initialMap.forEach((key, values) -> {
        values.forEach(value -> result.computeIfAbsent(value, x -> new ArrayList<>()).add(key));
    });

2
我刚写了一个答案(先在我的IDE上试了一下),但它没有通过编译。然后你发布了一个看起来和我的完全一样的答案,但是你的通过了编译。我找不出区别,直到我在比较工具中将它们进行比较,发现我发明了一个新类 - SimplyEntry... +1 - Eran
@Eran 我说实话,我根本没有编译第一个版本... :) 实际上,我更喜欢第二个变体。 - Eugene
@Eugene 为了可读性,我会选择第二种解决方案 :) - Taras Velykyy
不错!这是Lambda Hands-on Lab“挑战”部分中的一个练习,我(和一些同事)在过去几年中在多个会议上进行了演示。我们基于流的解决方案本质上是相同的,只是该练习使用了Map<K,Set<V>>。(还有缩进。):-) https://github.com/stuart-marks/LambdaHOLv2 - Stuart Marks

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接