Combining two <String, Integer> cards with the Java 8 Stream API

I have two (or more) Map<String, Integer> objects. I would like to combine them with the Java 8 Stream API so that the values ​​for the shared keys are maximum 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 validation method green?

I played with collect and Collectors for a while without any success.

( ImmutableMap and newArrayList owned by Google Guava.)

+44
java merge java-8 java-stream
Apr 13 '14 at 3:09
source share
6 answers
 @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); } 
+62
Apr 13 '14 at 5:27
source share
 Map<String, Integer> mx = new HashMap<>(m1); m2.forEach((k, v) -> mx.merge(k, v, Integer::max)); 
+46
Apr 13 '14 at 8:38
source share
 mx = list.stream().collect(HashMap::new, (a, b) -> b.forEach((k, v) -> a.merge(k, v, Integer::max)), Map::putAll); 

This covers the general case for any list of sizes and should work with any types, just change Integer::max and / or HashMap::new as desired.

If you don't care what value appears in the merge, there is a much cleaner solution:

 mx = list.stream().collect(HashMap::new, Map::putAll, Map::putAll); 

And as general methods:

 public static <K, V> Map<K, V> mergeMaps(Stream<? extends Map<K, V>> stream) { return stream.collect(HashMap::new, Map::putAll, Map::putAll); } public static <K, V, M extends Map<K, V>> M mergeMaps(Stream<? extends Map<K, V>> stream, BinaryOperator<V> mergeFunction, Supplier<M> mapSupplier) { return stream.collect(mapSupplier, (a, b) -> b.forEach((k, v) -> a.merge(k, v, mergeFunction)), Map::putAll); } 
+12
Aug 06 '14 at 18:08
source share

I added my contribution to the proton package library, which contains utilities for the Stream API. Here, how you could achieve what you want:

 Map<String, Integer> mx = MapStream.ofMaps(m1, m2).mergeKeys(Integer::max).collect(); 

Basically, mergeKeys will collect key-value pairs on a new map (providing a merge function is optional, otherwise you will get a Map<String, List<Integer>> ) and call stream() in entrySet() to get a new MapStream . Then use collect() to get the resulting map.

+1
Dec 28 '14 at 13:27
source share

Using StreamEx , you can:

 StreamEx.of(m1, m2) .flatMapToEntry(x -> x) .grouping(IntCollector.max()) 
+1
Oct 11 '16 at 10:44
source share

This is engineering, you can only do:

 map3 = new HashMap<>(); map3.putAll(map1); map3.putAll(map2); 
-3
Nov 02 '16 at 17:30
source share



All Articles