I have two (or more) Map<String, Integer>
objects. I'd like to merge them with Java 8 Stream API in a way that values for common keys should be the maximum of the values.
@Test public void test14() throws Exception { Map<String, Integer> m1 = ImmutableMap.of("a", 2, "b", 3); Map<String, Integer> m2 = ImmutableMap.of("a", 3, "c", 4); List<Map<String, Integer>> list = newArrayList(m1, m2); Map<String, Integer> mx = list.stream()... // TODO Map<String, Integer> expected = ImmutableMap.of("a", 3, "b", 3, "c", 4); assertEquals(expected, mx); }
How can I make this test method green?
I've played with collect
and Collectors
for a while without any success.
(ImmutableMap
and newArrayList
are from Google Guava.)
We can use putAll() method on any map instance and put all the entries from the given map into it. First, we created an empty output map and then added all the entries from both of the maps into it. As a result, we got merged entries from both of our maps.
Assuming that both maps contain the same set of keys, and that you want to "combine" the values, the thing you would be looking for is a Pair class, see here for example. You simply iterate one of the maps; and retrieve values from both maps; and create a Pair; and push that in your result map.
Java HashMap merge() The Java HashMap merge() method inserts the specified key/value mapping to the hashmap if the specified key is already not present. If the specified key is already associated with a value, the method replaces the old value with the result of the specified function.
The easiest way to merge two maps in Groovy is to use + operator. This method is straightforward - it creates a new map from the left-hand-side and right-hand-side maps.
We will demonstrate merging two maps with different approaches. Java 8 adds a new merge () function into the java.util.Map interface. Learn and master in Java 8 features at Java 8 Tutorial with Examples.
First, we transform map1 and map2 into a single stream. Next, we convert the stream into the map. As we can see, the last argument of toMap () is a merging function.
Java 8 adds a new merge () function into the java.util.Map interface. Here is how the merge () function works: If the specified key is not already associated with a value or the value is null, it associates the key with the given value. Otherwise, it replaces the value with the results of the given remapping function.
The Stream API in Java 8 can also provide an easy solution to our problem. First, we need to combine our Map instances into one Stream. That's exactly what Stream.concat () operation does: Stream combined = Stream.concat (map1.entrySet ().stream (), map2.entrySet ().stream ());
@Test public void test14() throws Exception { Map<String, Integer> m1 = ImmutableMap.of("a", 2, "b", 3); Map<String, Integer> m2 = ImmutableMap.of("a", 3, "c", 4); Map<String, Integer> mx = Stream.of(m1, m2) .map(Map::entrySet) // converts each map into an entry set .flatMap(Collection::stream) // converts each set into an entry stream, then // "concatenates" it in place of the original set .collect( Collectors.toMap( // collects into a map Map.Entry::getKey, // where each entry is based Map.Entry::getValue, // on the entries in the stream Integer::max // such that if a value already exist for // a given key, the max of the old // and new value is taken ) ) ; /* Use the following if you want to create the map with parallel streams Map<String, Integer> mx = Stream.of(m1, m2) .parallel() .map(Map::entrySet) // converts each map into an entry set .flatMap(Collection::stream) // converts each set into an entry stream, then // "concatenates" it in place of the original set .collect( Collectors.toConcurrentMap( // collects into a map Map.Entry::getKey, // where each entry is based Map.Entry::getValue, // on the entries in the stream Integer::max // such that if a value already exist for // a given key, the max of the old // and new value is taken ) ) ; */ Map<String, Integer> expected = ImmutableMap.of("a", 3, "b", 3, "c", 4); assertEquals(expected, mx); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With