【问题标题】:How to putAll on Java hashMap contents of one to another, but not replace existing keys and values?java - 如何将Java hashMap内容的全部放在另一个上,但不替换现有的键和值?
【发布时间】:2011-11-03 21:41:10
【问题描述】:

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

最好的方法是什么?

我想改为迭代 keySet 并检查它是否存在,我会

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

【问题讨论】:

    标签: java dictionary hashmap


    【解决方案1】:

    看起来你愿意创建一个临时的Map,所以我会这样做:

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

    这里,patch 是您要添加到 target 地图的地图。

    感谢Louis Wasserman,,这是一个利用 Java 8 中新方法的版本:

    patch.forEach(target::putIfAbsent);
    

    【讨论】:

    • 在这种情况下,您无需执行removeAll,因为无论如何它们都会被覆盖。
    • @Reverend Gonzo:被什么覆盖了?
    • @luksmir 不,这将删除应该保留的现有条目。
    • 嗨!为什么 mapWithValues.putAll(mapWithAnotherValues) 不起作用?
    • @erickson 更紧凑的 Java 8 版本:patch.forEach(target::putIfAbsent)
    【解决方案2】:

    使用 GuavaMaps 类的实用方法来计算 2 个映射的差异,您可以在一行中完成,方法签名可以更清楚地说明您要完成的工作:

    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());
    }
    

    【讨论】:

      【解决方案3】:

      只需迭代并添加:

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

      编辑添加:

      如果您可以对 a 进行更改,您也可以这样做:

      a.putAll(b)
      

      a 将拥有您所需要的一切。 (b 中的所有条目以及a 中不在b 中的所有条目)

      【讨论】:

      • 1.) entrySet() 返回 Set&lt;Map.Entry&gt;。 2.) contains(...)for java.util.Map 没有方法。
      • 没有更聪明的方法吗?像 Collections 实用程序一样吗?我讨厌到处都是 for 循环。
      • @AntonioP:到处都是 for 循环?有一个 for 循环,它尽可能简单。
      • +1 然后,我认为,当 Maps 不使用原始类型时才有效。让自己对 Map.Entry 有点糊涂了 :-)
      • @Reverend Gonzo,啊,在代码的其他地方。 :) 不会 .putAll 替换 a 的现有键和值吗?从这个意义上说,这似乎是最直接的方式。
      【解决方案4】:

      如果您在@erickson 的解决方案中更改地图顺序,只需一行即可完成:

      mapWithNotSoImportantValues.putAll( mapWithImportantValues );
      

      在这种情况下,您将 mapWithNotSoImportantValues 中的值替换为具有相同键的 mapWithImportantValues 中的值。

      【讨论】:

        【解决方案5】:

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

        开始,您可以使用Map#merge(K key, V value, BiFunction remappingFunction),它使用remappingFunction 将一个值合并到Map 中,以防在您想要放入该对的Map 中找到密钥。

        // 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 中,并在出现重复antry 的情况下保留原始值。

        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
        

        【讨论】:

          【解决方案6】:
          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);
          }}
          

          【讨论】:

            【解决方案7】:

            在 Java 8 中,有这个 API 方法可以满足您的要求。

            map.putIfAbsent(key, value)
            

            如果指定的键尚未与值关联(或映射为 null),则将其与给定值关联并返回 null,否则返回当前值。

            【讨论】:

            • 我们可以有 putAllIfAbsent 吗?这就是我需要的?
            【解决方案8】:

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

            mapToInsert.forEach(originalMap::putIfAbsent);
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-09-21
              • 2021-10-26
              • 2012-05-09
              • 2020-04-06
              • 2012-04-12
              相关资源
              最近更新 更多