Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 493
Melike Ttkn Avatar asked Mar 04 '15 22:03

Melike Ttkn


People also ask

Can Hashmaps have the same key?

Duplicates: HashSet doesn't allow duplicate values. HashMap stores key, value pairs and it does not allow duplicate keys.

Can HashMap store multiple values for same key?

The Map interface stores the elements as key-value pairs. It does not allow duplicate keys but allows duplicate values. HashMap and LinkedHashMap classes are the widely used implementations of the Map interface. But the limitation of the Map interface is that multiple values cannot be stored against a single key.

How do I combine two Hashmaps?

Merge Two HashMaps Ignoring Duplicate Keys This one is a simple solution. Use firstMap. putAll(secondMap) method that copies all of the mappings from the secondMap to firstMap. As we know hashmap does not allow duplicate keys.

Can a HashMap have multiple values for same key Java?

HashMap can be used to store key-value pairs. But sometimes you may want to store multiple values for the same key. For example: For Key A, you want to store - Apple, Aeroplane.


Video Answer


4 Answers

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));
like image 194
prunge Avatar answered Oct 22 '22 15:10

prunge


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.

like image 44
sprinter Avatar answered Oct 22 '22 15:10

sprinter


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;
}
like image 42
Lucas Ross Avatar answered Oct 22 '22 14:10

Lucas Ross


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)

like image 39
Zymus Avatar answered Oct 22 '22 14:10

Zymus