Aynı türleri içeren iki HashMap nesnesini nasıl birleştirebilirim?


241

Ben böyle HashMaptanımlanmış iki nesne var :

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

Ayrıca üçüncü bir HashMapnesnem var:

HashMap<String, Integer> map3;

Nasıl birleştirebilirsiniz map1ve map2bir araya map3?


16
Her iki haritada da bir anahtar varsa ne olmasını istediğinizi belirtmediniz.
Michael Scheper

Yanıtlar:


344
map3 = new HashMap<>();

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

1
teşekkür ederim, ben bir harita döndürmek ve başka bir harita ile birleştirmek ve aynı yöntemi agian uygulamak için bir yöntem kullanan bir for döngüsü içinde Haritalar birleştiriyorum. Bunun için putAll yöntemiyle boş gösterici istisnası alıyorum. try / catch bloğunun kullanılmasına yardımcı olmaz. ne yapmalıyım? Eğer koşul = eğer o = = o o zaman putAll uygulamak başka türlü uygulayın ve böylece ....
Mavin

1
Bir NPE alırsanız, görünüşe göre nesnelerinizden birini doğru şekilde başlatmadınız. Yığın izini catch bloğunda yazdırıyor musunuz? Böylece sorunun nerede ortaya çıktığını biliyorsunuz . Ancak yığın izini içeren tam ve tam kodu göndermediğiniz sürece, bunu kendi başınıza izlemeniz gerekir.
a_horse_with_no_name

95
Bu çözümle, her iki haritada da bir anahtar varsa, map2'deki değerin korunacağını ve map1'deki değerin kaybolacağını unutmayın.
Michael Scheper

5
@MichaelScheper: başka ne bekliyorsunuz? A anahtarları Maptanım gereği benzersizdir
a_horse_with_no_name

42
OPer'in ne beklediğini bilmiyorum. Belki de map1 değerlerinin öncelikli olmasını ya da bir istisna oluşturmasını ya da kesişen Tamsayılar üzerinde bazı 'birleştirme' işleminin yapılmasını bekler. Ya da belki, bu yeni başlayanların sorusu olduğu için, OPer'ın düşünmediği bir durumdur, bu durumda yorumum umarım faydalı olacaktır.
Michael Scheper

109

Yinelenen anahtarlarınız olmadığını veya yinelenen anahtarların değerlerinin map2üzerine yazmak için değerlerin olmasını map1istiyorsanız,

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

Değerlerin nasıl birleştirildiği üzerinde daha fazla kontrole ihtiyacınız varsa Map.merge, BiFunctionyinelenen anahtarlar için değerleri birleştirmek üzere kullanıcı tarafından sağlanan Java 8'e eklenen kullanabilirsiniz . mergeayrı ayrı anahtarlar ve değerler üzerinde çalışır, bu nedenle bir döngü veya kullanmanız gerekir Map.forEach. Burada yinelenen anahtarlar için dizeleri birleştiriyoruz:

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

Yinelenen anahtarlarınız olmadığını ve zorlamak istediğinizi biliyorsanız, aşağıdakileri atan bir birleştirme işlevi kullanabilirsiniz AssertionError:

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

Bu özel sorudan geri adım atarak Java 8 akış kitaplığı toMapve groupingBy Koleksiyoncular sağlar . Haritaları bir döngüde tekrar tekrar birleştiriyorsanız, hesabınızı akışları kullanacak şekilde yeniden yapılandırabilirsiniz; bu, hem kodunuzu netleştirebilir hem de paralel bir akış ve eşzamanlı toplayıcı kullanarak kolay paralellik sağlayabilir.


46

Java 8 Stream API kullanan tek astar:

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

Bu yöntemin faydaları arasında, aynı anahtara sahip değerlerle ilgilenecek bir birleştirme işlevini geçme yeteneği vardır, örneğin:

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

1
bu yinelenen anahtarlar için IllegalStateException özel durumunu oluşturacaktır
Arpit J.

1
@ArpitJ. ikinci varyasyonun bütün mesele bu. Bazen istisnayı istersiniz, bazen istemezsiniz.
Alex R

36

İki haritayı birleştirmek için Java 8 alternatif bir astar:

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

Yöntem referansı ile aynı:

defaultMap.forEach(destMap::putIfAbsent);

Veya üçüncü harita ile orijinal haritalar çözümü için idemponent:

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

Ve işte Guava ile iki haritayı hızlı değişmez bir harita ile birleştirmenin bir yolu :

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

Her iki haritada da bulunan değerlerin eşleme işleviyle birleştirilmesi gerektiğinde, bkz. Java 8 ile iki haritayı birleştirme.


32

Eğer son harita için mutability gerekmiyorsa, orada Guava en ImmutableMap kendi diliyle Builderve putAllyöntemi aksine, hangi Java'nın Maparayüz yöntemiyle , zincirleme edilebilir.

Kullanım örneği:

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

Tabii ki, bu yöntem daha genel olabilir, varargs kullanın ve putAll Mapsargümanlardan döngü vb. Ama bir konsept göstermek istedim.

Ayrıca, ImmutableMapve Builderbazı sınırlamaları (veya belki özellikleri?) Var:

  • null düşmanlar (fırlat NullPointerException- haritadaki herhangi bir anahtar veya değer null ise)
  • Oluşturucu yinelenen anahtarları kabul etmez ( IllegalArgumentExceptionyinelenen anahtarlar eklenirse atar ).



11

Ortak anahtarları paylaşabilecek iki haritayı birleştirmek için genel çözüm:

Yerinde:

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

Yeni bir haritayı iade etme:

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

Diğer haritalardan harita oluşturmak için sıklıkla kullandığım küçük bir snippet:

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

HashMap<String, List<Integer>>her iki hasheti birleştirmek ve aynı anahtarla eşleştirilmiş öğeleri kaybetmemek için kullanabilirsiniz .

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

çıktı:

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

2

Çok geç ama aynı sorunu yaşadığımda ne yaptığımı paylaşmama izin verin.

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

Aşağıdaki çıktıyı verir

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

Yinelenen öğeler eklenmeyecektir (yinelenen anahtarlar), hs3 yazdığımızda son 5 katma değer olacak ve sıçan olacak olan anahtar 5 için yalnızca bir değer elde edeceğiz. ** [Set, yinelenen anahtara izin vermeme özelliğine sahiptir, ancak değerler yinelenebilir]


0

Yöntem 1: Haritaları bir listeye koyun ve sonra katılın

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


}

Yöntem 2: Normal Harita Birleştirme

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

Harita için putAll işlevini aşağıdaki kodda açıklandığı gibi kullanabilirsiniz

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

Snippet'in altında birden fazla harita alınır ve birleştirilir.

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

Demo örnek bağlantısı.


-1

kullanabilirsiniz - addAll yöntemi

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

Ancak her zaman bu sorun vardır - eğer iki karma haritanızda herhangi bir anahtar varsa - o zaman ilk karma haritasından anahtarın değerini ikinci karma haritasından anahtarın değerine göre geçersiz kılar.

Daha güvenli tarafta olmak için - anahtar değerlerini değiştirin - tuşlarda önek veya sonek kullanabilirsiniz - (ilk karma harita için farklı önek / sonek ve ikinci karma harita için farklı önek / sonek)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.