我有两个HashMap对象,定义如下:
HashMap<String, Integer> map1 = new HashMap<String, Integer>();
HashMap<String, Integer> map2 = new HashMap<String, Integer>();
我还有第三个HashMap对象:
HashMap<String, Integer> map3;
如何将map1和map2合并为map3?
我有两个HashMap对象,定义如下:
HashMap<String, Integer> map1 = new HashMap<String, Integer>();
HashMap<String, Integer> map2 = new HashMap<String, Integer>();
我还有第三个HashMap对象:
HashMap<String, Integer> map3;
如何将map1和map2合并为map3?
当前回答
一个小片段,我经常使用从其他地图创建地图:
static public <K, V> Map<K, V> merge(Map<K, V>... args) {
final Map<K, V> buffer = new HashMap<>();
for (Map m : args) {
buffer.putAll(m);
}
return buffer;
}
其他回答
使用Java 8 Stream API的一行程序:
map3 = Stream.of(map1, map2).flatMap(m -> m.entrySet().stream())
.collect(Collectors.toMap(Entry::getKey, Entry::getValue))
该方法的好处之一是能够传递一个merge函数,该函数将处理具有相同键的值,例如:
map3 = Stream.of(map1, map2).flatMap(m -> m.entrySet().stream())
.collect(Collectors.toMap(Entry::getKey, Entry::getValue, Math::max))
你可以对其他类型使用Collection.addAll(),例如List, Set等。对于Map,您可以使用putAll。
如果最终的映射不需要可变性,可以使用Guava的ImmutableMap及其Builder和putAll方法,与Java的map接口方法相反,ImmutableMap可以被链接。
使用示例:
Map<String, Integer> mergeMyTwoMaps(Map<String, Integer> map1, Map<String, Integer> map2) {
return ImmutableMap.<String, Integer>builder()
.putAll(map1)
.putAll(map2)
.build();
}
当然,这个方法可以更通用,使用可变参数和循环从参数中putAll map等,但我想展示一个概念。
此外,ImmutableMap和它的构建器有一些限制(或者可能是功能?):
他们是空敌对(抛出NullPointerException -如果map中的任何键或值为空) 生成器不接受重复的键(如果添加了重复的键则抛出IllegalArgumentException)。
用于合并两个映射的Java 8替代一行程序:
defaultMap.forEach((k, v) -> destMap.putIfAbsent(k, v));
方法参考也一样:
defaultMap.forEach(destMap::putIfAbsent);
或原始地图解与第三个地图的幂分量:
Map<String, Integer> map3 = new HashMap<String, Integer>(map2);
map1.forEach(map3::putIfAbsent);
下面是一个用Guava将两个映射合并为快速不可变映射的方法,它可以进行最少的中间复制操作:
ImmutableMap.Builder<String, Integer> builder = ImmutableMap.<String, Integer>builder();
builder.putAll(map1);
map2.forEach((k, v) -> {if (!map1.containsKey(k)) builder.put(k, v);});
ImmutableMap<String, Integer> map3 = builder.build();
请参见使用Java 8合并两个映射,了解需要使用映射函数组合两个映射中的值的情况。
假设输入如下:
import java.util.stream.Stream;
import java.util.stream.Collectors;
import java.util.Map;
...
var m1 = Map.of("k1", 1, "k2", 2);
var m2 = Map.of("k3", 3, "k4", 4);
当你确定两个输入映射之间没有任何键冲突时,一个避免任何突变并产生不可变结果的简单表达式可以是:
var merged = Stream.concat(
m1.entrySet().stream(),
m2.entrySet().stream()
).collect(Collectors.toUnmodifiableMap(Map.Entry::getKey, Map.Entry::getValue));
在可能发生键冲突的情况下,我们可以提供一个lambda来指定如何去重复它们。例如,如果我们想保留最大的值,以防两个输入中都有一个条目,我们可以:
.collect(Collectors.toUnmodifiableMap(
Map.Entry::getKey,
Map.Entry::getValue,
Math::max)) // any function (Integer, Integer) -> Integer is ok here