合并两个列表值映射

4

有人知道如何在Java 8中合并两个这种类型的映射吗?

Map<String,  List<String>> map1--->["a",{1,2,3}]
Map<String,  List<String>> map2--->["a",{4,5,6}]

并获得合并的结果。
Map<String,  List<String>> map3--->["a",{1,2,3,4,5,6}]

我正在寻找一种非冗长的方法(如果存在的话)。我知道如何用老式的方式做。

祝好。


1
https://dev59.com/L2oy5IYBdhLWcg3wD5_H#25152991 - Alex - GlassEditor.com
是列表的映射,不一样。我之前看过这些帖子。 - paul
在我的情况下,情况更加复杂,因为地图是在迭代器内部创建的,所以我需要在每次迭代中将最后创建的地图与新地图合并。谢谢,但我仍然不知道如何在我的示例中使用它。也许你可以提供一个例子吗?我真的没看到。谢谢! - paul
2
如果您正在使用Guava,并且有ListMultimap,那么这只是putAll - Louis Wasserman
3个回答

6

这个方法的基本思路与这篇文章中的相同。你需要从第一个Map创建一个新的Map,然后遍历第二个Map,并使用merge(key, value, remappingFunction)将每个键与第一个Map合并。如果发生冲突,则应用重新映射函数:在这种情况下,它会取两个列表并将它们合并;如果没有冲突,则会将具有给定键和值的条目放入。

Map<String, List<String>> mx = new HashMap<>(map1);
map2.forEach((k, v) -> mx.merge(k, v, (l1, l2) -> {
    List<String> l = new ArrayList<>(l1);
    l.addAll(l2);
    return l;
}));

这是我找到的更简洁的代码,所以我会采用它!;) 谢谢! - paul
3
一个可替代的合并函数是(l1, l2) -> Stream.concat(l1.stream(),l2.stream()).collect(toList())。这是Java目前最简单的方法(不使用第三方库)。 - Holger
这减少了合并函数的冗长,谢谢! - paul
2
@paul 这确实减少了冗长,但它更加复杂(因为它创建了流管道)。 - Tunaki
对我来说,速度比复杂性更重要。我想这是真的,虽然它不太冗长,但更昂贵。 - paul
如果性能很重要,更好的合并函数应该是(l1,l2)->{List<String> l = new ArrayList<>(l1.size()+l2.size()); l.addAll(l1); l.addAll(l2); return l;}以确保适当的初始容量。但问题是关于“非冗长方式”的... - Holger

1
你可以尝试这个方法,逐步将结构变平,直到你得到一个由地图键与列表值的元组流:
Map<K,List<V>> result = Stream.of(map1,map2) // Stream<Map<K,List<V>>>
    .flatMap(m -> m.entrySet().stream()) // Stream<Map.Entry<K,List<V>>>
    .flatMap(e -> e.getValue().stream() // Inner Stream<V>...
            .map(v -> new AbstractMap.SimpleImmutableEntry<>(e.getKey(), v))) 
    // ...flatmapped into an outer Stream<Map.Entry<K,V>>>
    .collect(Collectors.groupingBy(e -> e.getKey(), Collectors.mapping(e -> e.getValue(), Collectors.toList())));

另一个选项是通过在groupingBy的第二个参数中使用Collectors.reducing()来避免列表的内部流式处理。不过,我认为首先应该考虑接受的答案。


1

你需要使用Set而不是List,可以像这样做:

Map<String, Set<String>> map1--->["a",{1,2,3}]
Map<String, Set<String>> map2--->["a",{4,5,6}]

map1.forEach((k, v) -> v.addAll(map2.get(k) == null : new HashSet<> ? map2.get(k)));

除了假设可变集合并且不处理第二个映射中可能存在的键的情况外,我不明白为什么这需要使用Set。对于List来说,情况完全一样。 - Holger
因为使用列表,你会有重复的值。 - Oussama Zoghlami

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