Java stream join maps

Java Joy: Merge Maps Using Stream API

In Java we can merge a key/value pair into a Map with the merge method. The first parameter is the key, the second the value and the third parameter of the merge method is a remapping function that is applied when the key is already present in the Map instance. The remapping function has the value of the key in the original Map and the new value. We can define in the function what the resulting value should be. If we return null the key is ignored.

If we want to merge multiple Map instances we can use the Stream API. We want to convert the Map instances to a stream of Map.Entry instances which we then turn into a new Map instance with the toMap method from the class Collectors . The toMap method also takes a remapping function when there is a duplicate key. The function defines what the new value is based on the two values of the duplicate key that was encountered. We can choose to simply ignore one of the values and return the other value. But we can also do some computations in this function, for example creating a new value using both values.

In the following example we use the Stream API to merge multiple Map instances into a new Map using a remapping function for duplicate keys:

package com.mrhaki.sample; import java.util.Arrays; import java.util.HashSet; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; public class MapMerge { public static void main(String[] args) { Map first = Map.of('a', 2, 'b', 3, 'c', 4); Map second = Map.of('a', 10, 'c', 11); Map third = Map.of('a', 3, 'd', 100); // First we turn multiple maps into a stream of entries and // in the collect method we create a new map and define // a function to multiply the entry value when there is a // duplicate entry key. Map result = Stream.of(first, second, third) .flatMap(m -> m.entrySet().stream()) .collect( Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (value1, value2) -> value1 * value2)); // The values for duplicate keys are multiplied in the resulting map. assert Map.of('a', 60, 'b', 3, 'c', 44, 'd', 100).equals(result); // In this sample the value is a Java class Characteristic. // The function to apply when a key is duplicate will create // a new Characteristic instance contains all values. // The resulting map will contain all concatenated characteristic values // for each key. var langauges = Stream.of(Map.of("Java", new Characteristic("jvm")), Map.of("Clojure", new Characteristic("dynamic", "functional")), Map.of("Groovy", new Characteristic("jvm", "dynamic")), Map.of("Clojure", new Characteristic("jvm")), Map.of("Groovy", new Characteristic("dynamic")), Map.of("Java", new Characteristic("static"))) .flatMap(m -> m.entrySet().stream()) .collect( Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (c1, c2) -> c1.addCharateristics(c2.getValues()))); assert new Characteristic("static", "jvm").equals(langauges.get("Java")); assert new Characteristic("dynamic", "functional", "jvm").equals(langauges.get("Clojure")); assert new Characteristic("dynamic", "jvm").equals(langauges.get("Groovy")); } /** * Supporting class to store language characteristics. */ static class Characteristic { // Store unique characteristic value. private Set values = new HashSet<>(); Characteristic(String characteristic) { values.add(characteristic); } Characteristic(String. characteristics) { values.addAll(Arrays.asList(characteristics)); } Characteristic addCharateristics(Set characteristics) { values.addAll(characteristics); return this; } Set getValues() { return values; } @Override public boolean equals(final Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } final Characteristic that = (Characteristic) o; return Objects.equals(values, that.values); } @Override public int hashCode() { return Objects.hash(values); } } }

Источник

Читайте также:  Javascript click and touch

How to merge two maps in Java

There are multiple ways to merge or join two instances of the HashMap class in Java. In this article, you’ll learn to join maps with and without handling duplicate keys.

Let us say you have got the following two HashMap objects that you want to combine:

MapString, Integer> map1 = new HashMap>(); map1.put("A", 1); map1.put("B", 2); map1.put("C", 3); map1.put("F", 4); MapString, Integer> map2 = new HashMap>(); map2.put("A", 3); map2.put("B", 4); map2.put("D", 5); 

The Map.putAll() method provides a quick and simple solution to merge two maps. This method copies all key-value pairs from the second map to the first map. Since a HashMap object can not store duplicate keys, the Map.putAll() method override the value of duplicate keys in the first map with values from the second map.

// Merge second map with first map map1.putAll(map2); // Print new map System.out.println(map1); 

The Map.merge() method was introduced in Java 8 and is useful for joining maps with duplicate keys. This method takes three arguments as input: key, value, and a remapping function to merge values for duplicate keys. If the specified key is not already associated with a value or is associated with null , the Map.merge() method associates it with the given non-null value. Otherwise, the Map.merge() method replaces the value with the results of the given remapping function. If the result of the remapping function is null , it removes the key altogether. The following example demonstrates how you can combine the values of duplicate keys using the remapping function of Map.merge() :

// Merge second map with first map map2.forEach((key, value) -> map1.merge(key, value, (v1, v2) -> v1 + v2) ); // Print new map System.out.println(map1); // 

Notice the values of key B . It had value 2 in map1 and value 4 in map2 . After the merge, it has a combined value of 6 in the merged map. The remapping function allows you to write any merge logic that suits your needs.

The Stream.concat() method from the Stream API in Java 8 can also be used to combine two maps. As the name suggests, the Stream.concat() method combines the Map instances into one Stream object:

StreamMap.EntryString, Integer>> combined = Stream.concat(map1.entrySet().stream(), map2.entrySet().stream()); 
MapString, Integer> merged = combined.collect( Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); 

The above solution works fine as long as there are no duplicate keys. If it encounters any duplicate entry, it will throw an IllegalStateException exception. To handle duplicate entries, you can pass a merger function as a third parameter to the collector:

MapString, Integer> merged = combined.collect( Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> v1 + v2)); // Print new map System.out.println(merged); // 

Stream.of() is another method from the Stream API that can be used to merge two maps in Java 9 and above:

// Merge the second map with the first map MapString, Integer> merged = Stream.of(map1, map2) .flatMap(map -> map.entrySet().stream()) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> v1 + v2)); // Print new map System.out.println(merged); // 

In the above example, we first transform map1 and map2 into a unified stream with the help of Stream.of() and Stream.flatMap() methods. Next, we convert the stream into a map using a collector function. ✌️ Like this article? Follow me on Twitter and LinkedIn. You can also subscribe to RSS Feed.

You might also like.

Источник

Объединить две карты в Java

В этом посте мы обсудим, как объединить две карты одного типа в Java. Решение возвращает новую карту, содержащую все сопоставления на обеих картах. Операция слияния будет обрабатывать общие ключи, присутствующие в обеих картах.

1. Использование putAll() метод

Простое решение — использовать Map.putAll() метод для копирования всех сопоставлений с исходной карты на другую карту.

Обратите внимание, что если ключ k существует на обеих картах, значение в hm2 перезапишет значение в hm1 . т.е., map[k] = hm2[k] . Например,

Мы можем избежать лишнего вызова putAll() метод, передав первую карту в HashMap конструктор.

Если вам нужно добавить содержимое карты hm1 для отображения hm2 , вы можете просто сделать:

2. Использование Guava

Guava также предоставляет конструктор для создания неизменяемых экземпляров карты с использованием putAll() метод, последовательные вызовы которого могут быть объединены в цепочку:

3. Использование Java 8

В Java 8 и выше вы можете получить поток элементов обеих карт и вызвать Collectors.toMap() чтобы собрать все элементы карты в новую карту, применив к ней указанные функции отображения, чтобы помочь идентифицировать ключи и значения. Это показано ниже:

Приведенный выше код выдает java.lang.IllegalStateException если дубликат ключа присутствует в обеих картах. Чтобы справиться с этим, предоставьте функцию слияния для разрешения конфликтов между значениями, связанными с одним и тем же ключом.

Следующий код обеспечивает BinaryOperator для объединения значений повторяющихся ключей, где старое значение имеет приоритет над новым значением в потоке.

Источник

Оцените статью