Hugo Zaragoza
Hugo Zaragoza

Reputation: 601

adding the values of two maps when same key

Looking for a standard library function way in Java for adding the values in two maps based on their keys.

Map A: {a=1, b=2}
Map B: {a=2, c=3}

Resulting map:

Map C: {a=3, b=2, c=3}

I know this can be coded in a few lines. I also know functional programming is great for this. I am just wandering if there is a standard function or syntax people use out there.

Something like (but probably more generic than):

 public HashMap<String,Double> addValues(HashMap<String,Double> a, HashMap<String,Double> b) {
    HashMap<String,Double> ret = new HashMap<String,Double>(a);
    for (String s : b.keySet()) {
      if (ret.containsKey(s)) {
        ret.put(s, b.get(s) + ret.get(s));
      } else {
        ret.put(s, b.get(s));
      }
    }
    return ret;
  }

Upvotes: 6

Views: 8048

Answers (3)

Jamie Cockburn
Jamie Cockburn

Reputation: 7555

Here's a version that allows for any number of Maps to be combined:

public static Map<String, Integer> addKeys(Map<String, Integer>... maps) {
    Set<String> keys = new HashSet<String>();
    for (Map<String, Integer> map : maps)
        keys.addAll(map.keySet());

    Map<String, Integer> result = new HashMap<String, Integer>();
    for (String key : keys) {
        Integer value = 0;
        for (Map<String, Integer> map : maps)
            if (map.containsKey(key))
                value += map.get(key); 
        result.put(key, value);
    }
    return result;
}

Usage:

public static void main(String[] args){
    Map<String, Integer> a = new HashMap<String, Integer>();
    a.put("a", 1);
    a.put("b", 2);
    Map<String, Integer> b = new HashMap<String, Integer>();
    b.put("a", 2);
    b.put("c", 3);

    Map<String, Integer> c = addKeys(a, b);
    System.out.println(c);
}

Ouptut:

{b=2, c=3, a=3}

Unfortunately, it's not possible as far as I can see to create a generic method:

 public static <K, V extends Number> Map<K, V> addKeys(Class<V> cls, Map<K, V>... maps);

Because the Number class doesn't support the + operator. Which seems a bit daft to me...

Upvotes: 1

assylias
assylias

Reputation: 328618

An alternative which does essentially the same thing, using Java 8 new getOrDefault method:

Set<String> keys = new HashSet<> (a.keySet());
keys.addAll(b.keySet());

Map<String, Integer> c = new HashMap<>();
for (String k : keys) {
  c.put(k, a.getOrDefault(k, 0) + b.getOrDefault(k, 0));
}

But if using Java 8, you may as well stream the keys and make it a one liner:

Map<String, Object> c = Stream.concat(a.keySet().stream(), b.keySet().stream())
         .distinct()
         .collect(toMap(k -> k, k -> a.getOrDefault(k, 0) + b.getOrDefault(k, 0)));

Upvotes: 3

noMAD
noMAD

Reputation: 7844

I think what you are doing is just fine. I can think of one other way though, using a MultiMap. You can add all your elements to a multimap and then run a summation function over all the values for each key at the end.

Upvotes: 1

Related Questions