Pensez à fusionner plusieurs cartes en une seule carte. Finalement, il sera généralisé aux méthodes utilitaires suivantes.
// Map<K, V>[]Carte<K, V>Fusionner en
public static <K, V> Map<K, V> merge(BiFunction<? super V, ? super V, ? extends V> mergeFunction, Map<K, V>... maps)
// Map<K, V>[]Carte<K, R>Fusionner en
public static <K, V, R> Map<K, R> merge(Collector<V, ?, R> mergeCollector, Map<K, V>... maps)
// Map<K, List<V>>[]Carte<K, List<V>>Fusionner en
public static <K, V> Map<K, List<V>> merge(Map<K, List<V>>... maps)
Développez Map <K, V> []
to` Stream <Entry <K, V >> ʻet collectez-le, mais s'il y a plusieurs entrées avec des clés correspondantes, vous devez y penser au cas par cas. Doit être.
Les deux modèles suivants peuvent être grossièrement divisés.
--Merge using Collectors # toMap (): Répétez le traitement et le stockage des valeurs binaires avec les clés correspondantes avec la fonction de fusion --Fusion à l'aide de collecteurs # grounpingBy (): traitement par lots des valeurs de correspondance de clé dans les collecteurs inférieurs
S'il n'y a que deux cartes à fusionner, vous pouvez toujours le faire, nous vous recommandons donc d'utiliser un simple Collectors # toMap ().
Similaire à Map # merge (), Collectors # toMap () peut être utilisé si vous pouvez fusionner en répétant l'opération de fusion d'une nouvelle valeur avec une valeur déjà stockée.
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);
//Si les clés correspondent, prenez la somme des valeurs
Map<String, Integer> m3 =
Stream.of(m1, m2)
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.toMap(Entry::getKey, Entry::getValue, Integer::sum));
Le troisième argument de Map # merge () est BiFunction, tandis que le troisième argument de Collectors # toMap () est BinaryOperator (de la sous-interface), qui a quelques restrictions, mais cela ne devrait pas être un problème. Si vous avez déjà une fonction BiFunction que vous avez passée à Map # merge (), vous pouvez l'appliquer telle quelle en vous référant à BiFunction # apply ().
// Map#merge()Troisième type d'argument de
BiFunction<? super V, ? super V, ? extends V> remappingFunction = ...;
// Collectors#toMap()Converti au type du troisième argument de
BinaryOperator<V> mergeFunction = remappingFunction::apply;
S'il existe 3 valeurs ou plus pour la même clé et que vous souhaitez utiliser la moyenne de celles-ci comme valeur fusionnée, la méthode ci-dessus provoquera une erreur. De plus, étant donné que l'interface est BinaryOperator, il n'est pas possible d'effectuer une agrégation dans laquelle la valeur d'origine et la valeur résultante ont des types différents. Dans ce cas, vous devez utiliser Collectors # groupingBy () pour stocker la valeur de chaque clé de la collection et la convertir en résultat au niveau du module de finition.
//Si les clés correspondent, prenez la moyenne des valeurs
Map<String, Double> m4 =
Stream.of(m1, m2)
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.groupingBy(Entry::getKey, Collectors.averagingInt(Entry::getValue)));
Map <K, List <V >>
Comme exemple plus concret, fusionnons les données au format Map <K, List <V >>
par les deux méthodes ci-dessus.
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"));
//Fonction pour fusionner des listes
//Si vous en faites une méthode, vous pouvez vous référer à la méthode
BinaryOperator<List<String>> mergeList = (left, right) -> Stream.of(left, right).flatMap(List::stream).collect(Collectors.toList());
//Si cette mergeList est utilisée uniquement par Collector, l'implémentation suivante sera plus rapide et économisera de la mémoire.
// BinaryOperator<List<String>> mergeList = (l, r) -> {l.addAll(r); return l;};
// toMap()Fusionner avec
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>>liste<E>Collecteur à fusionner
// Stream<E>liste<E>Collectionneurs à regrouper#toList()Différent de
Collector<List<String>, ?, List<String>> collector = Collector.of(ArrayList::new, List::addAll, mergeList, Characteristics.IDENTITY_FINISH);
// groupingBy()Fusionner avec
Map<String, List<String>> lm4 =
Stream.of(lm1, lm2)
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.groupingBy(Entry::getKey, Collectors.mapping(Entry::getValue, collector)));
Enfin, je donnerai un exemple de version généralisée de ce qui précède et résumée dans une classe d'utilité.
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>Entrez un tableau de<K, V>Développer pour diffuser
@SafeVarargs
private static <K, V> Stream<Entry<K, V>> flatten(Map<K, V>... maps){
return Arrays.stream(maps).flatMap(map -> map.entrySet().stream());
}
//Fusionner les cartes dans différents types de cartes
@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)));
}
//Fusionner la carte dans la carte du même type
@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));
//Si vous souhaitez profiter de la version collector de l'implémentation
// 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);
}
//Fusionner la collection dans la liste
@SafeVarargs
private static <E> List<E> mergeIntoList(Collection<E>... collections){
return Arrays.stream(collections).flatMap(Collection::stream).collect(toList());
}
// Map<K, List<V>>Fusionner
@SafeVarargs
public static <K, V> Map<K, List<V>> merge(Map<K, List<V>>... maps){
return merge(MapMerger::mergeIntoList, maps);
}
//Exemple d'utilisation
public static void main(String[] args) {
//Exemple de données 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);
//somme
Map<String, Integer> m3 = merge(Integer::sum, m1, m2);
Map<String, Integer> m4 = merge(summingInt(Integer::intValue), m1, m2);
//moyenne
Map<String, Double> m5 = merge(averagingInt(Integer::intValue), m1, m2);
//Exemple de données 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"));
//Fusion homogène
Map<String, List<String>> lm3 = merge(lm1, lm2);
Map<String, List<String>> lm4 = merge(MapMerger::mergeIntoList, lm1, lm2);
// Map<String, String>Fusionner avec
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);
//production
Stream.of(m3, m4, m5).forEach(System.out::println);
Stream.of(lm3, lm4, lm5).forEach(System.out::println);
}
}
Recommended Posts