Merge Lists of Map to Map, Java 8 Style!

Reading Time: 3 minutes

Today, while doing my work and having fun programming, I came across a problem that looked pretty easy in the beginning, but after starting doing it, had to take help of Google and read from different sites to get to a nice implementation. So, let’s look at the problem and how to solve it.

The Problem

Well, you guys probably already have guessed what the problem was, and some of the geniuses might already have come up with 2-3 nice solutions. But for people like me, I will go ahead and explain the problem briefly. So, I had a list of maps, specifically, a list of maps of String and Long. What I wanted was to get a single map, which is the result of merging all these maps together. I also wanted to define a merge function, which basically would add values whenever the key of the maps is same, instead of just overwriting it. So, for example I have 3 maps as below –

Map1 = {"Apple"=2, "Banana"=3}
Map2 = {"Banana"=3, "Orange"=1}
Map3 = {"Guava"=7, "Apple"=4}

Then, I wanted the result to be –

ResultMap = {"Apple"=6, "Banana"=6, "Guava"=7, "Orange"=1}

So, let’s look at what the solution was.

The Solution

The solution is surprisingly very simple. We will use Java 8 streams to calculate the result. To calculate the result, we will first convert the list of maps to stream of maps using stream() function of list, and then we will use the reduce method of stream to perform operation on the current map and the accumulator map. In reduce we will get two maps to be merged, where we will use Collectors.toMap() with a merger function to merge the maps. So, let’s break down this process into smaller parts. Let’s first look at how will we merge just two maps.

Merging two maps

To merge two maps, we will –

  • Convert both the maps to streams, and concat the stream to get a single stream of entry set.
  • We will collect the stream using Collectors.toMap().
  • In Collectors.toMap(), we can specify the key that we want to have, the value, and a way to resolve a conflict situation, i.e., when the map already has the key we are trying to insert. This will be the third parameter to Collectors.toMap().
  • In that conflict situation, we will just sum the values and return it.

The code for the above process is as below

import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class MergeTwoMaps {
public static void main(String[] args) {
Map<String, Long> map = new HashMap<>();
map.put("Apple", 2L);
map.put("Banana", 2L);
Map<String, Long> map1 = new HashMap<>();
map1.put("Apple", 2L);
map1.put("Orange", 2L);
Map<String, Long> resultMap = Stream.concat(map.entrySet().stream(), map1.entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
(countInFirstMap, countInSecondMap) -> countInFirstMap + countInSecondMap));
System.out.println(resultMap);
}
}

The output of the above program is as below –

{Apple=4, Orange=2, Banana=2}

which is as expected. Now that we are clear on how to merge two maps, let’s see how to merge a list of maps.

Merging List of Maps

To merge a list of maps, we will

  • Convert the list to stream.
  • Then we will use the reduce function to get the current map and the map that has been constructed till now, or the accumulator map. For the first case, it will just be the first and the second map in the list.
  • Then in the reduce function, we can just merge the two maps using the way described in the previous section.

The code for this process is as below –

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class ListOfMapToMap {
public static void main(String[] args) {
Map<String, Long> map = new HashMap<>();
map.put("Apple", 2L);
map.put("Banana", 2L);
Map<String, Long> map1 = new HashMap<>();
map1.put("Apple", 2L);
map1.put("Orange", 2L);
Map<String, Long> map2 = new HashMap<>();
map1.put("Banana", 2L);
map1.put("Guava", 2L);
List<Map<String, Long>> mapList = new ArrayList<>();
mapList.add(map);
mapList.add(map1);
mapList.add(map2);
final Optional<Map<String, Long>> reduce = mapList.stream().reduce((firstMap, secondMap) -> {
return Stream.concat(firstMap.entrySet().stream(), secondMap.entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
(countInFirstMap, countInSecondMap) -> countInFirstMap + countInSecondMap));
});
System.out.println(reduce.get());
}
}

The result of the above program as below –

{Guava=2, Apple=4, Orange=2, Banana=4}

Do remember that reduce() returns us an optional, so please handle it nicely according to your use case.

That was the solution that I came up with for this problem. I am sure there are a lot of more possible solutions for this problem, and if you have any, please feel free to comment it. Will love to learn more.

I hope this blog was helpful for you and you got to learn something new today. Thanks for reading and happy blogging!

Written by 

Akshansh Jain is a Software Consultant having more than 1 year of experience. He is familiar with Java but also has knowledge of various other programming languages such as scala, HTML and C++. He is also familiar with different Web Technologies and Android programming. He is a passionate programmer and always eager to learn new technologies & apply them in respective projects.

1 thought on “Merge Lists of Map to Map, Java 8 Style!3 min read

  1. My solution:
    Map result = Arrays.asList(map1, map2, map3).stream()
    .flatMap(map -> map.entrySet().stream())
    .collect(Collectors.toMap(
    Map.Entry::getKey,
    Map.Entry::getValue,
    Integer::sum
    ));

Comments are closed.