Merge list of maps into a single map by summing values

stk020305 :

I have a class Values:

public class Values {
    private int count;
    private int values;
}

And a list of multiple maps of type Map<String, Values>

Map<String, Values> map1 = new HashMap<>();
        map1 .put("aaa", new Values(1, 10));
        map1 .put("bbb", new Values(5, 50));
        map1 .put("ccc", new Values(2, 30));

Map<String, Values> map2= new HashMap<>();
        map2.put("aaa", new Values(2, 20));
        map2.put("bbb", new Values(3, 50));
        map2.put("ccc", new Values(3, 10));

List<Map<String, Values>> list = Arrays.asList(map1, map2);

There could be any number of maps and any number of entries inside the maps, but the keys for the maps are always the same, only the values can differ. My example contains only 2 maps and only 3 entries for each map for clarity.

I want to obtain a single map with the same keys and with the Values objects as the sum of each "count" and each "value" in the objects, like this:

{
        aaa= {
            count = 3,
            value = 30
        },
        bbb= {
            count = 8,
            value = 100
        },
        ccc= {
            count = 6,
            value = 40
        }
    }

I am trying to achieve this using the Streams API, but I am stuck:

public static Map<String, Values> mergeMaps(List<Map<String, Values>> maps) {
        return maps.stream()
                .flatMap(m -> m.entrySet().stream()) ...?
    }

How can I group each entry by their keys and add up each count and each value into a single map?

Thank you in advance.

Eran :

You can collect the entries of your Stream with a toMap collector, with a merge function.

public static Map<String, Values> mergeMaps(List<Map<String, Values>> maps) {
    return maps.stream()
               .flatMap(m -> m.entrySet().stream())
               .collect(Collectors.toMap(Map.Entry::getKey,
                                         Map.Entry::getValue,
                                         (v1,v2) -> new Values(v1,v2)));
}

Assuming you have a Values constructor that takes two Values instances and creates an instance having the sums of the values.

Of course, you can write the merge function without that constructor. For example:

(v1,v2) -> new Values(v1.getCount()+v2.getCount(),v1.getValue()+v2.getValue())

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=36272&siteId=1