Ich habe zwei HashMap
-Objekte wie folgt definiert:
HashMap<String, Integer> map1 = new HashMap<String, Integer>();
HashMap<String, Integer> map2 = new HashMap<String, Integer>();
Ich habe auch ein drittes HashMap
-Objekt:
HashMap<String, Integer> map3;
Wie kann ich map1
und map2
in map3
zusammenführen?
map3 = new HashMap<>();
map3.putAll(map1);
map3.putAll(map2);
Wenn Sie wissen, dass Sie keine doppelten Schlüssel haben, oder Sie möchten, dass Werte in map2
Werte von map1
für doppelte Schlüssel überschreiben, können Sie einfach schreiben
map3 = new HashMap<>(map1);
map3.putAll(map2);
Wenn Sie mehr Kontrolle über die Kombination von Werten benötigen, können Sie Map.merge
, in Java 8 hinzugefügt verwenden. In diesem Fall werden Werte für doppelte Schlüssel mit einer benutzerdefinierten BiFunction
zusammengeführt. Da merge
für einzelne Schlüssel und Werte gilt, müssen Sie eine Schleife oder einen Map.forEach
verwenden. Hier verketten wir Strings für doppelte Schlüssel:
map3 = new HashMap<>(map1);
for (Map.Entry<String, String> e : map2.entrySet())
map3.merge(e.getKey(), e.getValue(), String::concat);
//or instead of the above loop
map2.forEach((k, v) -> map3.merge(k, v, String::concat));
Wenn Sie wissen, dass Sie keine doppelten Schlüssel haben und diese erzwingen möchten, können Sie eine Zusammenführungsfunktion verwenden, die eine AssertionError
auslöst:
map2.forEach((k, v) ->
map3.merge(k, v, (v1, v2) ->
{throw new AssertionError("duplicate values for key: "+k);}));
Die Java 8-Streams-Bibliothek stellt einen Schritt zurück von dieser spezifischen Frage und enthält toMap
und groupingBy
Collectors . Wenn Sie wiederholt Karten in einer Schleife zusammenführen, können Sie möglicherweise Ihre Berechnung für die Verwendung von Streams neu strukturieren. Dies kann sowohl den Code klarstellen als auch eine einfache Parallelität mithilfe eines parallelen Streams und eines gleichzeitigen Collectors ermöglichen.
Einzeiler mit Java 8 Stream API:
map3 = Stream.of(map1, map2).flatMap(m -> m.entrySet().stream())
.collect(Collectors.toMap(Entry::getKey, Entry::getValue))
Zu den Vorteilen dieser Methode gehört die Möglichkeit, eine Merge-Funktion zu übergeben, die Werte behandelt, die denselben Schlüssel haben, beispielsweise:
map3 = Stream.of(map1, map2).flatMap(m -> m.entrySet().stream())
.collect(Collectors.toMap(Entry::getKey, Entry::getValue, Math::max))
Java 8 alternativer One-Liner zum Zusammenführen von zwei Karten:
defaultMap.forEach((k, v) -> destMap.putIfAbsent(k, v));
Das gleiche gilt für die Referenz der Methode:
defaultMap.forEach(destMap::putIfAbsent);
Oder Idemponent für originale Kartenlösung mit dritter Karte:
Map<String, Integer> map3 = new HashMap<String, Integer>(map2);
map1.forEach(map3::putIfAbsent);
Und hier ist ein Weg, um zwei Karten mit Guava in schnelles unveränderliches zusammenzuführen, das möglichst wenig Kopiervorgänge für Zwischenschritte ausführt:
ImmutableMap.Builder<String, Integer> builder = ImmutableMap.<String, Integer>builder();
builder.putAll(map1);
map2.forEach((k, v) -> {if (!map1.containsKey(k)) builder.put(k, v);});
ImmutableMap<String, Integer> map3 = builder.build();
Siehe auch Zusammenführen von zwei Karten mit Java 8 für Fälle, in denen die in beiden Karten vorhandenen Werte mit der Mapping-Funktion kombiniert werden müssen.
Wenn Sie für Ihre endgültige Karte keine Mutabilität benötigen, gibt es GuavasImmutableMap
mit ihren Builder
und putAll
-Methode zu Javas Map
-Schnittstellenmethode , kann verkettet werden.
Anwendungsbeispiel:
Map<String, Integer> mergeMyTwoMaps(Map<String, Integer> map1, Map<String, Integer> map2) {
return ImmutableMap.<String, Integer>builder()
.putAll(map1)
.putAll(map2)
.build();
}
Natürlich kann diese Methode generischer sein. Verwenden Sie varargs und loop, um putAll
Maps
von Argumenten usw. zu verwenden, aber ich wollte ein Konzept zeigen.
Außerdem haben ImmutableMap
und ihre Builder
einige Einschränkungen (oder möglicherweise Funktionen?):
NullPointerException
aus, wenn ein Schlüssel oder ein Wert in der Map null ist)IllegalArgumentException
, wenn doppelte Schlüssel hinzugefügt wurden).HashMap hat eine putAll
-Methode.
http://download.Oracle.com/javase/6/docs/api/Java/util/HashMap.html
Sie können Collection.addAll () für andere Typen verwenden, z. List
, Set
, usw. Für Map
können Sie putAll
verwenden.
Generische Lösung zum Kombinieren von zwei Karten, die möglicherweise gemeinsame Schlüssel verwenden:
An Ort und Stelle:
public static <K, V> void mergeInPlace(Map<K, V> map1, Map<K, V> map2,
BinaryOperator<V> combiner) {
map2.forEach((k, v) -> map1.merge(k, v, combiner::apply));
}
Rückgabe einer neuen Karte:
public static <K, V> Map<K, V> merge(Map<K, V> map1, Map<K, V> map2,
BinaryOperator<V> combiner) {
Map<K, V> map3 = new HashMap<>(map1);
map2.forEach((k, v) -> map3.merge(k, v, combiner::apply));
return map3;
}
Sehr spät, aber lassen Sie mich mitteilen, was ich getan habe, als ich das gleiche Problem hatte.
Map<String, List<String>> map1 = new HashMap<>();
map1.put("India", Arrays.asList("Virat", "Mahi", "Rohit"));
map1.put("NZ", Arrays.asList("P1","P2","P3"));
Map<String, List<String>> map2 = new HashMap<>();
map2.put("India", Arrays.asList("Virat", "Mahi", "Rohit"));
map2.put("NZ", Arrays.asList("P1","P2","P4"));
Map<String, List<String>> collect4 = Stream.of(map1, map2)
.flatMap(map -> map.entrySet().stream())
.collect(
Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(strings, strings2) -> {
List<String> newList = new ArrayList<>();
newList.addAll(strings);
newList.addAll(strings2);
return newList;
}
)
);
collect4.forEach((s, strings) -> System.out.println(s+"->"+strings));
Es gibt die folgende Ausgabe
NZ->[P1, P2, P3, P1, P2, P4]
India->[Virat, Mahi, Rohit, Virat, Mahi, Rohit]
sie können HashMap<String, List<Integer>>
verwenden, um beide Hashmaps zusammenzuführen und zu vermeiden, dass Elemente verloren gehen, die mit demselben Schlüssel gekoppelt sind.
HashMap<String, Integer> map1 = new HashMap<>();
HashMap<String, Integer> map2 = new HashMap<>();
map1.put("key1", 1);
map1.put("key2", 2);
map1.put("key3", 3);
map2.put("key1", 4);
map2.put("key2", 5);
map2.put("key3", 6);
HashMap<String, List<Integer>> map3 = new HashMap<>();
map1.forEach((str, num) -> map3.put(str, new ArrayList<>(Arrays.asList(num))));
//checking for each key if its already in the map, and if so, you just add the integer to the list paired with this key
for (Map.Entry<String, Integer> entry : map2.entrySet()) {
Integer value = entry.getValue();
String key = entry.getKey();
if (map3.containsKey(key)) {
map3.get(key).add(value);
} else {
map3.put(key, new ArrayList<>(Arrays.asList(value)));
}
}
map3.forEach((str, list) -> System.out.println("{" + str + ": " + list + "}"));
ausgabe:
{key1: [1, 4]}
{key2: [2, 5]}
{key3: [3, 6]}
Ein kleines Snippet verwende ich sehr oft, um Karten aus anderen Karten zu erstellen:
static public <K, V> Map<K, V> merge(Map<K, V>... args) {
final Map<K, V> buffer = new HashMap<>();
for (Map m : args) {
buffer.putAll(m);
}
return buffer;
}
Wenn Sie die dritte Map so behalten möchten, dass Änderungen an den Einträgen nicht in den anderen Maps wiedergegeben werden.
HashMap<String, Integer> map3 = new HashMap<String, Integer>();
map3.putAll(map1);
map3.putAll(map2);
Methode 1: fügen Sie Karten in einer Liste ein, und verbinden Sie dann
public class Test15 {
public static void main(String[] args) {
Map<String, List<String>> map1 = new HashMap<>();
map1.put("London", Arrays.asList("A", "B", "C"));
map1.put("Wales", Arrays.asList("P1", "P2", "P3"));
Map<String, List<String>> map2 = new HashMap<>();
map2.put("Calcutta", Arrays.asList("Protijayi", "Gina", "Gini"));
map2.put("London", Arrays.asList( "P4", "P5", "P6"));
map2.put("Wales", Arrays.asList( "P111", "P5555", "P677666"));
System.out.println(map1);System.out.println(map2);
// put the maps in an ArrayList
List<Map<String, List<String>>> maplist = new ArrayList<Map<String,List<String>>>();
maplist.add(map1);
maplist.add(map2);
/*
<T,K,U> Collector<T,?,Map<K,U>> toMap(
Function<? super T,? extends K> keyMapper,
Function<? super T,? extends U> valueMapper,
BinaryOperator<U> mergeFunction)
*/
Map<String, List<String>> collect = maplist.stream()
.flatMap(ch -> ch.entrySet().stream())
.collect(
Collectors.toMap(
//keyMapper,
Entry::getKey,
//valueMapper
Entry::getValue,
// mergeFunction
(list_a,list_b) -> Stream.concat(list_a.stream(), list_b.stream()).collect(Collectors.toList())
));
System.out.println("Final Result(Map after join) => " + collect);
/*
{Wales=[P1, P2, P3], London=[A, B, C]}
{Calcutta=[Protijayi, Gina, Gini], Wales=[P111, P5555, P677666], London=[P4, P5, P6]}
Final Result(Map after join) => {Calcutta=[Protijayi, Gina, Gini], Wales=[P1, P2, P3, P111, P5555, P677666], London=[A, B, C, P4, P5, P6]}
*/
}//main
}
Methode 2: normale Kartenzusammenführung
public class Test15 {
public static void main(String[] args) {
Map<String, List<String>> map1 = new HashMap<>();
map1.put("London", Arrays.asList("A", "B", "C"));
map1.put("Wales", Arrays.asList("P1", "P2", "P3"));
Map<String, List<String>> map2 = new HashMap<>();
map2.put("Calcutta", Arrays.asList("Protijayi", "Gina", "Gini"));
map2.put("London", Arrays.asList( "P4", "P5", "P6"));
map2.put("Wales", Arrays.asList( "P111", "P5555", "P677666"));
System.out.println(map1);System.out.println(map2);
/*
<T,K,U> Collector<T,?,Map<K,U>> toMap(
Function<? super T,? extends K> keyMapper,
Function<? super T,? extends U> valueMapper,
BinaryOperator<U> mergeFunction)
*/
Map<String, List<String>> collect = Stream.of(map1,map2)
.flatMap(ch -> ch.entrySet().stream())
.collect(
Collectors.toMap(
//keyMapper,
Entry::getKey,
//valueMapper
Entry::getValue,
// mergeFunction
(list_a,list_b) -> Stream.concat(list_a.stream(), list_b.stream()).collect(Collectors.toList())
));
System.out.println("Final Result(Map after join) => " + collect);
/*
{Wales=[P1, P2, P3], London=[A, B, C]}
{Calcutta=[Protijayi, Gina, Gini], Wales=[P111, P5555, P677666], London=[P4, P5, P6]}
Final Result(Map after join) => {Calcutta=[Protijayi, Gina, Gini], Wales=[P1, P2, P3, P111, P5555, P677666], London=[A, B, C, P4, P5, P6]}
*/
}//main
}
HashMap<Integer,String> hs1 = new HashMap<>();
hs1.put(1,"ram");
hs1.put(2,"sita");
hs1.put(3,"laxman");
hs1.put(4,"hanuman");
hs1.put(5,"geeta");
HashMap<Integer,String> hs2 = new HashMap<>();
hs2.put(5,"rat");
hs2.put(6,"lion");
hs2.put(7,"tiger");
hs2.put(8,"fish");
hs2.put(9,"hen");
HashMap<Integer,String> hs3 = new HashMap<>();//Map is which we add
hs3.putAll(hs1);
hs3.putAll(hs2);
System.out.println(" hs1 : " + hs1);
System.out.println(" hs2 : " + hs2);
System.out.println(" hs3 : " + hs3);
Doppelte Elemente werden nicht hinzugefügt (dh doppelte Schlüssel), da beim Drucken von hs3 nur ein Wert für Schlüssel 5 ausgegeben wird, der als letzter Wert hinzugefügt wird, und es handelt sich um eine Ratte. ** [Set hat die Eigenschaft, dass der doppelte Schlüssel nicht zulässig ist, Werte jedoch dupliziert werden können]
Sie können die Funktion putAll für Map verwenden, wie im folgenden Code erläutert
HashMap<String, Integer> map1 = new HashMap<String, Integer>();
map1.put("a", 1);
map1.put("b", 2);
map1.put("c", 3);
HashMap<String, Integer> map2 = new HashMap<String, Integer>();
map1.put("aa", 11);
map1.put("bb", 12);
HashMap<String, Integer> map3 = new HashMap<String, Integer>();
map3.putAll(map1);
map3.putAll(map2);
map3.keySet().stream().forEach(System.out::println);
map3.values().stream().forEach(System.out::println);