【问题标题】:how to merge more than one hashmaps also sum the values of same key in java如何合并多个hashmaps还对java中相同键的值求和
【发布时间】:2015-05-06 03:04:01
【问题描述】:

我正在尝试合并多个哈希图也对相同键的值求和, 我想用玩具示例解释我的问题如下

    HashMap<String, Integer> m = new HashMap<>();
    HashMap<String, Integer> m2 = new HashMap<>();

    m.put("apple", 2);
    m.put("pear", 3);
    m2.put("apple", 9);
    m2.put("banana", 6);

我试过putall

m.putAll(m2);

输出如下 {香蕉=6,苹果=9,梨=3}

但它的结果不适用于这个问题。 我想输出为

{香蕉=6,苹果=11,梨=3}

我如何在 java 中得到这个结果?

【问题讨论】:

  • 我将想要的结果哈希图更清楚地重写为 {banana=6, apple=9+2, pear=3} 如果多个哈希图具有相同的键,则结果将是值的总和。如果其他哈希图没有相同的键,值不会改变,所有哈希图中的所有键都将在结果哈希图中及其值
  • 我喜欢每个后续答案如何变得越来越长,Java 专家表示它们是相应先前答案的更好版本。开始学习语言及其社区的好例子:)

标签: java merge hashmap


【解决方案1】:

这样的事情应该可以工作:

 for (Map.Entry<String, Integer> entry : map.entrySet()) {
    String map1_key = entry.getKey();
    int map1_value = entry.getValue();

    //check:
    if(map2.get(map1_key)!=null){
    int map2_value = map2.get(map1_key);
    //merge:
    map3.put(map1_key,map1_value+map2_value);
    }else{
    map3.put(map1_key,map1_value);
    }
}


  for (Map.Entry<String, Integer> entry2 : map2.entrySet()) {
        String map2_key = entry2.getKey();
        int map2_value = entry2.getValue();

        //check:
        if(map1.get(map2_key)!=null){
        int map1_value = map1.get(map2_key);
        //merge:
        map3.put(map2_key,map1_value+map2_value);
        }else{
        map3.put(map2_key,map2_value);
        }
    }

【讨论】:

  • 如果map1中的key在map2中没有值怎么办?那么只存在于 map2 中的条目呢?
  • 谢谢,但这不是我的问题的解决方案。如果所有地图都有相同的密钥,它会工作,但如果有与其他人不同的密钥,它就不会工作
  • 哦,对不起,我以为你说你需要根据相同的 KEYS 组合 VALUES
【解决方案2】:

如果键存在,则添加它的值。如果不插入。

这是一个将一张地图合并到另一张地图的简单示例:

Foo oldVal = map.get(key);
if oldVal == null
{
   map2.put(key, newVal);
}
else
{
   map2.put(key, newVal + oldVal);
}

显然,您必须遍历第一个地图,以便处理其中的所有条目,但这很简单。

【讨论】:

【解决方案3】:

这个方法应该可以做到(在 Java 5+ 中)

public static <K> Map<K, Integer> mergeAndAdd(Map<K, Integer>... maps) {
    Map<K, Integer> result = new HashMap<>();
    for (Map<K, Integer> map : maps) {
        for (Map.Entry<K, Integer> entry : map.entrySet()) {
            K key = entry.getKey();
            Integer current = result.get(key);
            result.put(key, current == null ? entry.getValue() : entry.getValue() + current);
        }
    }
    return result;
}

【讨论】:

    【解决方案4】:

    如果您使用的是 Java 8,则可以使用 Map 的新 merge 方法。

    m2.forEach((k, v) -> m.merge(k, v, (v1, v2) -> v1 + v2));
    

    【讨论】:

    • m 中没有出现在 m2 中的条目怎么办?
    • m 将包含合并的结果,此代码的输出:{banana=6, apple=11, pear=3}
    • 啊,我明白了 - 您正在合并到原始地图而不是创建新地图。我没有意识到这是 OP 的意图,但我现在在他的问题中看到了这一点。所以它本质上是依赖于原始地图的可变性。
    • 这也可以写成m2.forEach((k, v) -&gt; m.merge(k, v, Integer::sum));Long::sumDouble::sumFloat::sum,这取决于你的求和。
    【解决方案5】:

    这是 Java 8 流的一个非常好的用例。您可以连接条目流,然后将它们收集到新地图中:

    Map<String, Integer> combinedMap = Stream.concat(m1.entrySet().stream(), m2.entrySet().stream())
        .collect(Collectors.groupingBy(Map.Entry::getKey,
                 Collectors.summingInt(Map.Entry::getValue)));
    

    这个解决方案有很多好处,包括能够使其并行化、扩展到任意数量的地图以及能够在需要时对地图进行简单的过滤。它也不需要原始地图是可变的。

    【讨论】:

      【解决方案6】:

      这是我快速而肮脏的实现:

      import java.util.HashMap;
      import java.util.Map;
      
      public class MapMerger {
      
          public static void main(String[] args) {
              HashMap<String, Integer> m = new HashMap<>();
              HashMap<String, Integer> m2 = new HashMap<>();
      
              m.put("apple", 2);
              m.put("pear", 3);
              m2.put("apple", 9);
              m2.put("banana", 6);
      
              final Map<String, Integer> result = (new MapMerger()).mergeSumOfMaps(m, m2);
              System.out.println(result);
          }
      
          public Map<String, Integer> mergeSumOfMaps(Map<String, Integer>... maps) {
              final Map<String, Integer> resultMap = new HashMap<>();
              for (final Map<String, Integer> map : maps) {
                  for (final String key : map.keySet()) {
                      final int value;
                      if (resultMap.containsKey(key)) {
                          final int existingValue = resultMap.get(key);
                          value = map.get(key) + existingValue;
                      }
                      else {
                          value = map.get(key);
                      }
                      resultMap.put(key, value);
                  }
              }
              return resultMap;
          }
      }
      

      输出:

      {banana=6, apple=11, pear=3}
      

      有些事情你应该做(比如空检查),我不确定它是否是最快的。此外,这特定于整数。我尝试使用 Number 类的泛型来制作一个,但您需要为每种类型(字节、整数、短、长等)使用此方法

      【讨论】:

      • 它可能不是最快的,但对我来说更清晰易懂。非常感谢
      • 非常感谢您
      【解决方案7】:

      我改进了 Lucas Ross 的代码。而不是在函数中逐个输入地图,而是给所有地图一次以像这样使用哈希图的数组列表来运行

          public HashMap<String, Integer> mergeAndAdd(ArrayList<HashMap<String, Integer>> maplist) {
          HashMap<String, Integer> result = new HashMap<>();
          for (HashMap<String, Integer> map : maplist) {
              for (Map.Entry<String, Integer> entry : map.entrySet()) {
                  String key = entry.getKey();
                  Integer current = result.get(key);
                  result.put(key, current == null ? entry.getValue() : entry.getValue() + current);
              }
          }
          return result;
      }
      

      }

      它也有效。感谢大家

      【讨论】:

        【解决方案8】:

        假设你有很多 HashMap:HashMap&lt;String,Integer&gt; map1, map2, map3;

        然后你可以使用 Java 8 流:

        List<Map<String,Integer>> mapList = Arrays.asList(map1, map2, map3);
        
        Map<String,Integer> combinedMap = mapList.stream()
                .flatMap(map -> map.entrySet().stream())
                .collect(Collectors.groupingBy(Entry::getKey,
                        Collectors.summingInt(Entry::getValue)));
        

        【讨论】:

          猜你喜欢
          • 2013-06-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-08-28
          • 2011-04-04
          • 1970-01-01
          • 2011-10-27
          相关资源
          最近更新 更多