Come posso combinare due oggetti HashMap contenenti gli stessi tipi?


241

ne ho due HashMap oggetti definiti in questo modo:

HashMap<String, Integer> map1 = new HashMap<String, Integer>();
HashMap<String, Integer> map2 = new HashMap<String, Integer>();

Ne ho anche un terzo HashMap oggetto:

HashMap<String, Integer> map3;

Come posso unire map1e map2riunirci map3?


16
Non hai dichiarato cosa vuoi che accada se esiste una chiave in entrambe le mappe.
Michael Scheper,

Risposte:


344
map3 = new HashMap<>();

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

1
grazie, sto unendo le mappe in un ciclo for che utilizza un metodo per restituire una mappa e devo fonderla con un'altra mappa e applicare lo stesso metodo agian. Per questo, ottengo un'eccezione del puntatore null con il metodo putAll. non aiuta a usare il blocco try / catch. cosa dovrei fare? Sono applicabile se condizione, che se size == o quindi non si applica putTutti gli altri si applicano e così via ....
Mavin,

1
Se ottieni un NPE, apparentemente non hai inizializzato correttamente uno dei tuoi oggetti. Stampate lo stacktrace nel blocco catch? Quindi sai dove sorge il problema. Ma a meno che non pubblichi il codice completo ed esatto, inclusa la traccia dello stack, dovrai rintracciarlo da solo.
a_horse_with_no_name

95
Notare che, con questa soluzione, se esiste una chiave in entrambe le mappe, il valore in map2 verrà conservato e il valore in map1 andrà perso.
Michael Scheper,

5
@MichaelScheper: cos'altro ti aspetti? Le chiavi in ​​a Mapsono per definizione uniche
a_horse_with_no_name il

42
Non so cosa si aspetti dall'OPer. Forse si aspetta che i valori di map1 abbiano la precedenza, o che venga generata un'eccezione o che venga eseguita un'operazione di fusione su Integer intersecanti. O forse, poiché questa è una domanda per principianti, questo è un caso che l'OPer non aveva preso in considerazione, nel qual caso il mio commento sarebbe stato utile.
Michael Scheper,

109

Se sai di non avere chiavi duplicate o di voler map2sovrascrivere i valori map1per le chiavi duplicate, puoi semplicemente scrivere

map3 = new HashMap<>(map1);
map3.putAll(map2);

Se è necessario un maggiore controllo sulla modalità di combinazione dei valori, è possibile utilizzare Map.merge, aggiunto in Java 8, che utilizza un fornito dall'utenteBiFunction per unire i valori per le chiavi duplicate. mergefunziona su singole chiavi e valori, quindi è necessario utilizzare un ciclo o Map.forEach. Qui concateniamo stringhe per chiavi duplicate:

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

Se sai di non avere chiavi duplicate e desideri applicarle, puoi utilizzare una funzione di unione che genera un AssertionError :

map2.forEach((k, v) ->
    map3.merge(k, v, (v1, v2) ->
        {throw new AssertionError("duplicate values for key: "+k);}));

Facendo un passo indietro rispetto a questa domanda specifica, la libreria di flussi Java 8 fornisce toMape groupingBy Collezionisti . Se stai unendo ripetutamente le mappe in un ciclo, potresti essere in grado di ristrutturare il tuo calcolo per utilizzare gli stream, che possono sia chiarire il tuo codice che abilitare il parallelismo semplice utilizzando un flusso parallelo e un raccoglitore simultaneo.


46

One-liner con API Java 8 Stream:

map3 = Stream.of(map1, map2).flatMap(m -> m.entrySet().stream())
       .collect(Collectors.toMap(Entry::getKey, Entry::getValue))

Tra i vantaggi di questo metodo c'è la possibilità di passare una funzione di unione, che gestirà i valori che hanno la stessa chiave, ad esempio:

map3 = Stream.of(map1, map2).flatMap(m -> m.entrySet().stream())
       .collect(Collectors.toMap(Entry::getKey, Entry::getValue, Math::max))

1
questo genererà IllegalStateException per chiavi duplicate
Arpit J.

1
@ArpitJ. questo è il punto centrale della seconda variazione. A volte vuoi l'eccezione, a volte no.
Alex R

36

One-liner alternativo a Java 8 per unire due mappe:

defaultMap.forEach((k, v) -> destMap.putIfAbsent(k, v));

Lo stesso con riferimento al metodo:

defaultMap.forEach(destMap::putIfAbsent);

O idemponente per la soluzione di mappe originali con terza mappa:

Map<String, Integer> map3 = new HashMap<String, Integer>(map2);
map1.forEach(map3::putIfAbsent);

Ed ecco un modo per unire due mappe in una veloce immutabile con Guava che fa il meno possibile operazioni di copia intermedie:

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();

Vedi anche Unisci due mappe con Java 8 per i casi in cui i valori presenti in entrambe le mappe devono essere combinati con la funzione di mappatura.


32

Se non hai bisogno della mutabilità per la tua mappa finale, c'è Guava ImmutableMap con il suo Buildere il suo putAllmetodo che, a differenza del Mapmetodo di interfaccia di Java , può essere incatenato.

Esempio di utilizzo:

Map<String, Integer> mergeMyTwoMaps(Map<String, Integer> map1, Map<String, Integer> map2) {
  return ImmutableMap.<String, Integer>builder()
      .putAll(map1)
      .putAll(map2)
      .build();
}

Naturalmente, questo metodo può essere più generico, usare varargs e loop to putAll Maps da argomenti ecc. Ma volevo mostrare un concetto.

Inoltre, ImmutableMape Builderha alcune limitazioni (o forse funzionalità?):

  • sono nulli ostili (lancio NullPointerException - se qualsiasi chiave o valore nella mappa è nullo)
  • Il costruttore non accetta chiavi duplicate (genera IllegalArgumentExceptionse sono state aggiunte chiavi duplicate).



11

Soluzione generica per combinare due mappe che possono eventualmente condividere chiavi comuni:

A posto:

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));
}

Restituzione di una nuova mappa:

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

2

Un piccolo frammento che utilizzo molto spesso per creare mappe da altre mappe:

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

2

puoi usare HashMap<String, List<Integer>>per unire entrambi gli hashmap ed evitare di perdere elementi accoppiati con la stessa chiave.

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 + "}"));

produzione:

{key1: [1, 4]}
{key2: [2, 5]}
{key3: [3, 6]}

2

Molto tardi, ma lasciami condividere ciò che ho fatto quando ho avuto lo stesso problema.

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

Fornisce il seguente output

NZ->[P1, P2, P3, P1, P2, P4]
India->[Virat, Mahi, Rohit, Virat, Mahi, Rohit]

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

Gli oggetti duplicati non verranno aggiunti (ovvero chiavi duplicate) poiché quando stamperemo hs3 otterremo un solo valore per la chiave 5 che sarà l'ultimo valore aggiunto e sarà ratto. ** [Il set ha la proprietà di non consentire la chiave duplicata ma i valori possono essere duplicati]


0

Metodo 1: mettere le mappe in un elenco e quindi unire

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


}

Metodo 2: unione Mappa normale

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

Puoi usare la funzione putAll per Map come spiegato nel codice qui sotto

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

Lo snippet sottostante prende più di una mappa e le combina.

 private static <K, V> Map<K, V> combineMaps(Map<K, V>... maps) {
        if (maps == null || maps.length == 0) {
            return Collections.EMPTY_MAP;
        }

        Map<K, V> result = new HashMap<>();

        for (Map<K, V> map : maps) {
            result.putAll(map);
        }
        return result;
    }

Link di esempio dimostrativo .


-1

puoi usare il metodo addAll

http://download.oracle.com/javase/6/docs/api/java/util/HashMap.html

Ma c'è sempre questo problema che - se le tue due mappe hash hanno una chiave uguale - allora sovrascriverà il valore della chiave dalla prima mappa hash con il valore della chiave dalla seconda mappa hash.

Per essere sul lato più sicuro - modifica i valori delle chiavi - puoi usare il prefisso o il suffisso sulle chiavi - (prefisso / suffisso diverso per la prima mappa hash e prefisso / suffisso diverso per la seconda mappa hash)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.