Ziehen Sie in Betracht, mehrere Karten zu einer Karte zusammenzuführen. Schließlich wird es auf die folgenden Dienstprogrammmethoden verallgemeinert.
// Map<K, V>[]Karte<K, V>Vereinen
public static <K, V> Map<K, V> merge(BiFunction<? super V, ? super V, ? extends V> mergeFunction, Map<K, V>... maps)
// Map<K, V>[]Karte<K, R>Vereinen
public static <K, V, R> Map<K, R> merge(Collector<V, ?, R> mergeCollector, Map<K, V>... maps)
// Map<K, List<V>>[]Karte<K, List<V>>Vereinen
public static <K, V> Map<K, List<V>> merge(Map<K, List<V>>... maps)
Erweitern Sie Map <K, V> []
aufStream <Eintrag <K, V >>
und sammeln Sie es. Wenn jedoch mehrere Einträge mit übereinstimmenden Schlüsseln vorhanden sind, müssen Sie von Fall zu Fall darüber nachdenken. Muss sein.
Die folgenden zwei Muster können grob unterteilt werden.
--Merge using Collectors # toMap (): Wiederholen Sie die Verarbeitung und Speicherung von Binärwerten mit übereinstimmenden Schlüsseln mit der Merge-Funktion --Merge using Collectors # grounpingBy (): Batch-Prozessschlüssel-übereinstimmende Werte in niedrigeren Collectors
Wenn nur zwei Maps zusammengeführt werden müssen, können Sie dies auch tun. Wir empfehlen daher die Verwendung eines einfachen Collectors # toMap ().
Ähnlich wie bei Map # merge () kann Collectors # toMap () verwendet werden, wenn die Zusammenführung durch Wiederholen des Vorgangs zum Zusammenführen eines neuen Werts mit einem bereits gespeicherten Wert durchgeführt werden kann.
Map<String, Integer> m1 = new HashMap<>();
m1.put("a", 1);
m1.put("b", 2);
m1.put("c", 3);
Map<String, Integer> m2 = new HashMap<>();
m2.put("a", 100);
m2.put("b", 200);
m2.put("c", 300);
//Wenn die Schlüssel übereinstimmen, nehmen Sie die Summe der Werte
Map<String, Integer> m3 =
Stream.of(m1, m2)
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.toMap(Entry::getKey, Entry::getValue, Integer::sum));
Das dritte Argument von Map # merge () ist BiFunction, während das dritte Argument von Collectors # toMap () BinaryOperator (der Subschnittstelle) ist, das einige Einschränkungen aufweist, aber kein Problem darstellen sollte. Wenn Sie bereits eine BiFunction haben, die Sie an Map # merge () übergeben haben, können Sie sie unverändert anwenden, indem Sie auf BiFunction # apply () verweisen.
// Map#merge()Dritter Argumenttyp von
BiFunction<? super V, ? super V, ? extends V> remappingFunction = ...;
// Collectors#toMap()Umgerechnet auf den Typ des dritten Arguments von
BinaryOperator<V> mergeFunction = remappingFunction::apply;
Wenn es 3 oder mehr Werte für denselben Schlüssel gibt und Sie den Durchschnitt davon als zusammengeführten Wert verwenden möchten, verursacht die obige Methode einen Fehler. Da die Schnittstelle BinaryOperator ist, ist es auch nicht möglich, eine Aggregation durchzuführen, bei der der ursprüngliche Wert und der resultierende Wert unterschiedliche Typen haben. In einem solchen Fall müssen Sie Collectors # groupingBy () verwenden, um den Wert für jeden Schlüssel in der Sammlung zu speichern und ihn im Finisher in das Ergebnis zu konvertieren.
//Wenn die Schlüssel übereinstimmen, nehmen Sie den Durchschnitt der Werte
Map<String, Double> m4 =
Stream.of(m1, m2)
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.groupingBy(Entry::getKey, Collectors.averagingInt(Entry::getValue)));
Als konkreteres Beispiel lassen Sie uns die Daten im Format "Map <K, List
Map<String, List<String>> lm1 = new HashMap<>();
lm1.put("a", Arrays.asList("a1","a2","a3"));
lm1.put("b", Arrays.asList("b1","b2","b3"));
lm1.put("c", Arrays.asList("c1","c2","c3"));
Map<String, List<String>> lm2 = new HashMap<>();
lm2.put("a", Arrays.asList("a3","a4","a5"));
lm2.put("e", Arrays.asList("e1","e2","e3"));
lm2.put("f", Arrays.asList("f1","f2","f3"));
//Funktion zum Zusammenführen von Listen
//Wenn Sie es zu einer Methode machen, können Sie auf die Methode verweisen
BinaryOperator<List<String>> mergeList = (left, right) -> Stream.of(left, right).flatMap(List::stream).collect(Collectors.toList());
//Wenn diese MergeList nur von Collector verwendet wird, ist die folgende Implementierung schneller und spart Speicher.
// BinaryOperator<List<String>> mergeList = (l, r) -> {l.addAll(r); return l;};
// toMap()Verbinden mit
Map<String, List<String>> lm3 =
Stream.of(lm1, lm2)
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.toMap(Entry::getKey, Entry::getValue, mergeList));
// Stream<List<E>>Aufführen<E>Sammler zum Zusammenführen
// Stream<E>Aufführen<E>Sammler zum Aggregieren#toList()Anders als
Collector<List<String>, ?, List<String>> collector = Collector.of(ArrayList::new, List::addAll, mergeList, Characteristics.IDENTITY_FINISH);
// groupingBy()Verbinden mit
Map<String, List<String>> lm4 =
Stream.of(lm1, lm2)
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.groupingBy(Entry::getKey, Collectors.mapping(Entry::getValue, collector)));
Abschließend werde ich ein Beispiel für eine Verallgemeinerung des Obigen geben und in einer Utility-Klasse zusammengefasst.
import static java.util.stream.Collectors.*;
import java.util.*;
import java.util.Map.Entry;
import java.util.function.*;
import java.util.stream.*;
public class MapMerger {
// Map<K, V>Geben Sie ein Array von ein<K, V>Zum Streamen erweitern
@SafeVarargs
private static <K, V> Stream<Entry<K, V>> flatten(Map<K, V>... maps){
return Arrays.stream(maps).flatMap(map -> map.entrySet().stream());
}
//Führen Sie Karten zu verschiedenen Kartentypen zusammen
@SafeVarargs
public static <K, V, R> Map<K, R> merge(Collector<V, ?, R> collector, Map<K, V>... maps){
return flatten(maps).collect(groupingBy(Entry::getKey, mapping(Entry::getValue, collector)));
}
//Karte in Karte des gleichen Typs zusammenführen
@SafeVarargs
public static <K, V> Map<K, V> merge(BiFunction<? super V, ? super V, ? extends V> mergeFunction, Map<K, V>... maps) {
return flatten(maps).collect(toMap(Entry::getKey, Entry::getValue, mergeFunction::apply));
//Wenn Sie die Collector-Version der Implementierung nutzen möchten
// Function<List<V>, V> finisher = values -> values.stream().reduce(mergeFunction::apply).get();
// Collector<V, ?, V> collector = Collector.of(ArrayList::new, List::add, MapMerger::mergeIntoList, finisher, Characteristics.IDENTITY_FINISH);
// return merge(collector, maps);
}
//Sammlung in Liste zusammenführen
@SafeVarargs
private static <E> List<E> mergeIntoList(Collection<E>... collections){
return Arrays.stream(collections).flatMap(Collection::stream).collect(toList());
}
// Map<K, List<V>>Verschmelzen
@SafeVarargs
public static <K, V> Map<K, List<V>> merge(Map<K, List<V>>... maps){
return merge(MapMerger::mergeIntoList, maps);
}
//Anwendungsbeispiel
public static void main(String[] args) {
//Beispieldaten 1
Map<String, Integer> m1 = new HashMap<>();
m1.put("a", 1);
m1.put("b", 2);
m1.put("c", 3);
Map<String, Integer> m2 = new HashMap<>();
m2.put("a", 100);
m2.put("b", 200);
m2.put("c", 300);
//Summe
Map<String, Integer> m3 = merge(Integer::sum, m1, m2);
Map<String, Integer> m4 = merge(summingInt(Integer::intValue), m1, m2);
//durchschnittlich
Map<String, Double> m5 = merge(averagingInt(Integer::intValue), m1, m2);
//Beispieldaten 2
Map<String, List<String>> lm1 = new HashMap<>();
lm1.put("a", Arrays.asList("a1","a2","a3"));
lm1.put("b", Arrays.asList("b1","b2","b3"));
lm1.put("c", Arrays.asList("c1","c2","c3"));
Map<String, List<String>> lm2 = new HashMap<>();
lm2.put("a", Arrays.asList("a3","a4","a5"));
lm2.put("e", Arrays.asList("e1","e2","e3"));
lm2.put("f", Arrays.asList("f1","f2","f3"));
//Homogene Verschmelzung
Map<String, List<String>> lm3 = merge(lm1, lm2);
Map<String, List<String>> lm4 = merge(MapMerger::mergeIntoList, lm1, lm2);
// Map<String, String>Zusammenführen mit
Collector<List<String>, ?, String> collector = Collector.<List<String>, List<String>, String>of(
ArrayList::new,
List::addAll,
MapMerger::mergeIntoList,
List::toString);
Map<String, String> lm5 = merge(collector, lm1, lm2);
//Ausgabe
Stream.of(m3, m4, m5).forEach(System.out::println);
Stream.of(lm3, lm4, lm5).forEach(System.out::println);
}
}
Recommended Posts