Melike Ttkn
Melike Ttkn

Reputation: 191

how to merge more than one hashmaps also sum the values of same key in java

ı am trying to merge more than one hashmaps also sum the values of same key, ı want to explain my problem with toy example as follows

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

ı tried putall

m.putAll(m2);

output is as follows {banana=6, apple=9, pear=3}

but its result is not true for this problem. ı want to output as

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

how can ı get this result in java?

Upvotes: 18

Views: 19468

Answers (8)

Nano
Nano

Reputation: 178

Assume that you have many HashMaps: Map<String,Integer> map1, map2, map3;

Then you can use Java 8 streams:

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

Upvotes: 1

Melike Ttkn
Melike Ttkn

Reputation: 191

ı improve Lucas Ross's code. in stead of enter map by one by in function ı give all maps one times to function with arraylist of hashmap like that

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

}

it works too. thanks to everbody

Upvotes: 1

Zymus
Zymus

Reputation: 1698

Here's my quick and dirty implementation:

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

Output:

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

There are some things you should do (like null checking), and I'm not sure if it's the fastest. Also, this is specific to integers. I attempted to make one using generics of the Number class, but you'd need this method for each type (byte, int, short, longer, etc)

Upvotes: 1

sprinter
sprinter

Reputation: 27946

This is a very nice use case for Java 8 streams. You can concatentate the streams of entries and then collect them in a new map:

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

There are lots of nice things about this solution, including being able to make it parallel, expanding to as many maps as you want and being able to trivial filter the maps if required. It also does not require the orginal maps to be mutable.

Upvotes: 12

Lucas Ross
Lucas Ross

Reputation: 1089

This method should do it (in 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;
}

Upvotes: 1

prunge
prunge

Reputation: 23238

If you are using Java 8, you can use the new merge method of Map.

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

Upvotes: 35

Petro
Petro

Reputation: 3652

Something like this should work:

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

Upvotes: 0

ventsyv
ventsyv

Reputation: 3532

If the key exists, add to it's value. If not insert.

Here is a simple example which merges one map into another:

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

Obviously you have to loop over the first map so you can process all of it's entries but that's trivial.

Upvotes: 0

Related Questions