如何将一个Java hashMap中的内容全部放入另一个hashMap中,但不替换现有的键和值?

92

我需要将一个HashMap中的所有键和值复制到另一个HashMap中,但不替换现有的键和值。

最好的方法是什么?

我在想,可以不用迭代keySet并检查它是否存在,而是:

Map temp = new HashMap(); // generic later
temp.putAll(Amap);
A.clear();
A.putAll(Bmap);
A.putAll(temp);
8个回答

122

看起来您想创建一个临时的 Map,那么我会这样做:

Map tmp = new HashMap(patch);
tmp.keySet().removeAll(target.keySet());
target.putAll(tmp);

这里的patch是您要添加到target map中的映射。

感谢Louis Wasserman,以下是利用Java 8中的新方法的版本:

patch.forEach(target::putIfAbsent);

@luksmir 不行,那会删除应该保留的现有条目。 - erickson
你好!为什么 mapWithValues.putAll(mapWithAnotherValues) 不起作用? - betomoretti
@betomoretti 因为如果两个映射都有一个键的值,那么它将用另一个值替换原始值。这将违反“不替换现有键和值”的要求。 - erickson
@erickson,mapWithValues.putAll(mapWithAnotherValues) 这样的写法是不正确的,因为 void mapWithValues 将无法正常工作。因此,这不是一个好的解决方案。 - betomoretti
17
一种更为简洁的Java 8版本是:patch.forEach(target::putIfAbsent)。其中,将 patch 集合中的元素逐个传递给 target.putIfAbsent() 方法进行操作。 - Louis Wasserman
显示剩余3条评论

16

使用GuavaMaps类的实用方法来计算两个Map之间的差异,你可以在一行代码中完成它,使用这种方法签名可以更清楚地表明你试图实现什么:

public static void main(final String[] args) {
    // Create some maps
    final Map<Integer, String> map1 = new HashMap<Integer, String>();
    map1.put(1, "Hello");
    map1.put(2, "There");
    final Map<Integer, String> map2 = new HashMap<Integer, String>();
    map2.put(2, "There");
    map2.put(3, "is");
    map2.put(4, "a");
    map2.put(5, "bird");

    // Add everything in map1 not in map2 to map2
    map2.putAll(Maps.difference(map1, map2).entriesOnlyOnLeft());
}

8

只需迭代并添加:

for(Map.Entry e : a.entrySet())
  if(!b.containsKey(e.getKey())
    b.put(e.getKey(), e.getValue());

补充说明:

如果你可以对a进行更改,你也可以执行以下操作:

a.putAll(b)

您需要的是完全匹配 b 中的所有条目和 a 中不在 b 中的所有条目。


1.) entrySet()返回一个Set<Map.Entry>。 2.) java.util.Map中没有contains(...)方法。 - Fabian Barney
难道没有更聪明的方法吗?比如集合实用程序之类的?我讨厌到处都有for循环。 - rapadura
1
@AntonioP:到处都是for循环?实际上只有一个for循环,而且它非常简单明了。 - Reverend Gonzo
+1 然后,只有在使用 Maps 而不是原始类型时才有效,我想。我自己对 Map.Entry 有点困惑 :-) - Fabian Barney
@Reverend Gonzo,啊,在代码的其他地方。 :) .putAll会替换a中现有的键和值吗? 我会选择这种方式,因为它似乎是最直接的方法。 - rapadura
显示剩余2条评论

6
如果您按照@erickson的解决方案改变地图顺序,您只需要一行代码就可以完成:
mapWithNotSoImportantValues.putAll( mapWithImportantValues );

在这种情况下,您将使用与mapWithImportantValues相同的键从mapWithNotSoImportantValues中替换值。

5

使用Map#merge的Java 8解决方案

开始,您可以使用Map#merge(K key, V value, BiFunction remappingFunction)将值合并到Map中,在该Map中找到键时,使用remappingFunction将其与要放入其中的键值对合并。

// using lambda
newMap.forEach((key, value) -> map.merge(key, value, (oldValue, newValue) -> oldValue));

// using for-loop
for (Map.Entry<Integer, String> entry: newMap.entrySet()) {
    map.merge(entry.getKey(), entry.getValue(), (oldValue, newValue) -> oldValue);
}

代码迭代newMap条目(keyvalue),并通过方法merge将每个条目合并到map中。如果出现重复的键,则会触发remappingFunction,在这种情况下,它会使用先前(原始)oldValue值而不是被重写的值。
使用此解决方案,您无需临时Map
让我们举一个例子,将newMap的条目合并到map中,并在出现重复条目时保留原始值。
Map<Integer, String> newMap = new HashMap<>();
newMap.put(2, "EVIL VALUE");                         // this will NOT be merged into
newMap.put(4, "four");                               // this WILL be merged into
newMap.put(5, "five");                               // this WILL be merged into

Map<Integer, String> map = new HashMap<>();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");

newMap.forEach((k, v) -> map.merge(k, v, (oldValue, newValue) -> oldValue));

map.forEach((k, v) -> System.out.println(k + " " + v));
1 one
2 two
3 three
4 four
5 five

2

正如其他人所说,您可以使用 putIfAbsent。遍历要插入的地图中的每个条目,并在原始地图上调用此方法:

mapToInsert.forEach(originalMap::putIfAbsent);

2

在Java 8中,有这个API方法可以实现你的要求。

map.putIfAbsent(key, value)

如果指定的键还没有与值相关联(或者已映射为 null),则将其与给定的值进行关联并返回 null,否则返回当前值。


2
我们可以有putAllIfAbsent吗?这正是我所需要的。 - user1735921

2
public class MyMap {

public static void main(String[] args) {

    Map<String, String> map1 = new HashMap<String, String>();
    map1.put("key1", "value1");
    map1.put("key2", "value2");
    map1.put("key3", "value3");
    map1.put(null, null);

    Map<String, String> map2 = new HashMap<String, String>();
    map2.put("key4", "value4");
    map2.put("key5", "value5");
    map2.put("key6", "value6");
    map2.put("key3", "replaced-value-of-key3-in-map2");
    // used only if map1 can be changes/updates with the same keys present in map2.
    map1.putAll(map2);

    // use below if you are not supposed to modify the map1.
    for (Map.Entry e : map2.entrySet())
        if (!map1.containsKey(e.getKey()))
            map1.put(e.getKey().toString(), e.getValue().toString());
    System.out.println(map1);
}}

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