wake-up-neo.com

Wie kann ich zwei HashMap-Objekte mit denselben Typen kombinieren?

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?

206
Mavin
map3 = new HashMap<>();

map3.putAll(map1);
map3.putAll(map2);
294

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 groupingByCollectors . 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.

92
Jeffrey Bosboom

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))
40

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.

29
Vadzim

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 putAllMaps 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?):

  • sie sind null feindlich (werfen Sie NullPointerException aus, wenn ein Schlüssel oder ein Wert in der Map null ist)
  • Der Generator akzeptiert keine doppelten Schlüssel (wirft IllegalArgumentException, wenn doppelte Schlüssel hinzugefügt wurden).
26
Xaerxess
25
hvgotcodes

Sie können Collection.addAll () für andere Typen verwenden, z. List, Set, usw. Für Map können Sie putAll verwenden.

17
fastcodejava

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;
}
11
ZhekaKozlov

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]
1
Ishan Bhatt

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]}
1
Omer Vishlitzky

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;
}
1
Thomas Decaux

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


}
0
Soudipta Dutta
    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]

0
Karunesh

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);
0
P Mittal