Bagaimana saya bisa menggabungkan dua objek HashMap yang mengandung tipe yang sama?

241

Saya memiliki dua HashMapobjek yang didefinisikan seperti ini:

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

Saya juga punya HashMapobjek ketiga :

HashMap<String, Integer> map3;

Bagaimana saya bisa bergabung map1dan map2bersama map3?

Mavin
sumber
16
Anda belum menyatakan apa yang ingin terjadi jika kunci ada di kedua peta.
Michael Scheper

Jawaban:

344
map3 = new HashMap<>();

map3.putAll(map1);
map3.putAll(map2);
seekor kuda tanpa nama
sumber
1
terima kasih, saya menggabungkan peta dalam for for loop yang menggunakan metode mengembalikan peta dan perlu menggabungkannya ke peta lain dan menerapkan metode yang sama agian. Untuk ini, saya mendapatkan pengecualian pointer nol dengan metode putAll. tidak membantu menggunakan blok try / catch. apa yang harus saya lakukan? Saya berlaku jika kondisi, bahwa jika ukuran == o maka jangan menerapkan putAll lain menerapkannya dan seterusnya ....
Mavin
1
Jika Anda mendapatkan NPE, maka ternyata Anda tidak menginisialisasi salah satu objek dengan benar. Apakah Anda mencetak stacktrace di catch block? Jadi, Anda tahu di mana masalahnya muncul. Tetapi kecuali jika Anda memposting kode lengkap dan tepat termasuk jejak tumpukan Anda harus melacaknya sendiri.
a_horse_with_no_name
95
Perhatikan bahwa, dengan solusi ini, jika ada kunci di kedua peta, nilai di map2 akan dipertahankan dan nilai di map1 hilang.
Michael Scheper
5
@MichaelScheper: apa lagi yang Anda harapkan? Kunci dalam a Mapadalah definisi unik
a_horse_with_no_name
42
Saya tidak tahu apa yang diharapkan OPer. Mungkin dia mengharapkan nilai map1 didahulukan, atau pengecualian untuk dilemparkan, atau untuk beberapa operasi 'penggabungan' yang akan dilakukan pada memotong Integers. Atau mungkin, karena ini adalah pertanyaan pemula, ini adalah kasus yang belum dipertimbangkan OPer, dalam hal ini komentar saya semoga bermanfaat.
Michael Scheper
109

Jika Anda tahu Anda tidak memiliki kunci duplikat, atau Anda ingin nilai map2untuk menimpa nilai dari map1kunci duplikat, Anda bisa menulis

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

Jika Anda membutuhkan kontrol lebih besar tentang bagaimana nilai-nilai digabungkan, Anda bisa menggunakan Map.merge, ditambahkan di Java 8, yang menggunakan yang disediakan pengguna BiFunctionuntuk menggabungkan nilai untuk kunci duplikat. mergeberoperasi pada kunci dan nilai individual, jadi Anda harus menggunakan loop atau Map.forEach. Di sini kami merangkai string untuk kunci duplikat:

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

Jika Anda tahu Anda tidak memiliki kunci duplikat dan ingin menerapkannya, Anda bisa menggunakan fungsi gabungan yang melempar AssertionError:

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

Mengambil langkah mundur dari pertanyaan khusus ini, perpustakaan Java 8 stream menyediakan toMapdan groupingBy Kolektor . Jika Anda berulang kali menggabungkan peta dalam satu lingkaran, Anda mungkin dapat merestrukturisasi perhitungan Anda untuk menggunakan stream, yang keduanya dapat memperjelas kode Anda dan memungkinkan paralelisme mudah menggunakan aliran paralel dan kolektor bersamaan.

Jeffrey Bosboom
sumber
46

One-liner menggunakan Java 8 Stream API:

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

Di antara manfaat metode ini adalah kemampuan untuk melewatkan fungsi penggabungan, yang akan menangani nilai-nilai yang memiliki kunci yang sama, misalnya:

map3 = Stream.of(map1, map2).flatMap(m -> m.entrySet().stream())
       .collect(Collectors.toMap(Entry::getKey, Entry::getValue, Math::max))
Vitalii Fedorenko
sumber
1
ini akan membuang IllegalStateException untuk kunci duplikat
Arpit J.
1
@ArpitJ. itulah inti dari variasi kedua. Terkadang Anda menginginkan pengecualian, terkadang tidak.
Alex R
36

Java 8 alternatif satu-liner untuk menggabungkan dua peta:

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

Sama dengan referensi metode:

defaultMap.forEach(destMap::putIfAbsent);

Atau idemponent untuk solusi peta asli dengan peta ketiga:

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

Dan di sini adalah cara untuk menggabungkan dua peta menjadi satu peta cepat berubah dengan Guava yang paling tidak memungkinkan operasi penyalinan antara:

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

Lihat juga Menggabungkan dua peta dengan Java 8 untuk kasus-kasus ketika nilai-nilai yang ada di kedua peta perlu dikombinasikan dengan fungsi pemetaan.

Vadzim
sumber
32

Jika Anda tidak memerlukan mutabilitas untuk peta akhir Anda, ada Guava ImmutableMap dengan Builderdan putAllmetode yang, berbeda dengan metode antarmuka JavaMap , dapat dirantai.

Contoh penggunaan:

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

Tentu saja, metode ini bisa lebih generik, gunakan varargs dan loop ke putAll Mapsdari argumen dll, tetapi saya ingin menunjukkan konsep.

Juga, ImmutableMapdan Buildermemiliki beberapa keterbatasan (atau mungkin fitur?):

  • mereka bermusuhan nol (melempar NullPointerException- jika ada kunci atau nilai di peta adalah nol)
  • Builder tidak menerima kunci duplikat (melempar IllegalArgumentExceptionjika kunci duplikat ditambahkan).
Xaerxess
sumber
21

Anda bisa menggunakan Collection.addAll () untuk tipe lain, mis List. Set, Dll. Untuk Map, Anda bisa menggunakan putAll.

fastcodejava
sumber
11

Solusi umum untuk menggabungkan dua peta yang mungkin dapat berbagi kunci umum:

Di tempat:

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

Mengembalikan peta baru:

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;
}
ZhekaKozlov
sumber
2

Cuplikan kecil yang sering saya gunakan untuk membuat peta dari peta lain:

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

Anda bisa menggunakan HashMap<String, List<Integer>>untuk menggabungkan kedua hashmaps dan menghindari kehilangan elemen yang dipasangkan dengan kunci yang sama.

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

keluaran:

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

Sangat terlambat, tetapi izinkan saya berbagi apa yang saya lakukan ketika saya memiliki masalah yang sama.

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

Ini memberikan output berikut

NZ->[P1, P2, P3, P1, P2, P4]
India->[Virat, Mahi, Rohit, Virat, Mahi, Rohit]
Ishan Bhatt
sumber
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);

Item duplikat tidak akan ditambahkan (yaitu kunci duplikat) seperti ketika kita akan mencetak hs3 kita hanya akan mendapatkan satu nilai untuk kunci 5 yang akan menjadi nilai tambah terakhir dan itu akan menjadi tikus. ** [Set memiliki properti yang tidak mengizinkan kunci duplikat tetapi nilainya dapat digandakan]

Karunesh
sumber
0

Metode 1: Masukkan peta dalam Daftar dan kemudian bergabung

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


}

Metode 2: Penggabungan Peta Normal

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


}
Soudipta Dutta
sumber
0

Anda dapat menggunakan fungsi putAll untuk Peta seperti yang dijelaskan dalam kode di bawah ini

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

Cuplikan di bawah ini membutuhkan lebih dari satu peta dan menggabungkannya.

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

Tautan contoh demo .

Hari Krishna
sumber
-1

Anda dapat menggunakan - metode addAll

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

Tetapi selalu ada masalah ini bahwa - jika dua peta hash Anda memiliki kunci yang sama - maka itu akan menimpa nilai kunci dari peta hash pertama dengan nilai kunci dari peta hash kedua.

Agar berada di sisi yang lebih aman - ubah nilai kunci - Anda dapat menggunakan awalan atau akhiran pada tombol - (awalan / akhiran berbeda untuk peta hash pertama dan awalan / sufiks berbeda untuk peta hash kedua)

Ashish Shetkar
sumber