Làm cách nào để kết hợp hai đối tượng HashMap có chứa cùng loại?


240

Tôi có hai HashMapđối tượng được định nghĩa như vậy:

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

Tôi cũng có một HashMapđối tượng thứ ba :

HashMap<String, Integer> map3;

Làm thế nào tôi có thể hợp nhất map1map2cùng nhau thành map3?


16
Bạn chưa nói điều gì bạn muốn xảy ra nếu một khóa tồn tại trong cả hai bản đồ.
Michael Scheper

Câu trả lời:


343
map3 = new HashMap<>();

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

1
cảm ơn bạn, tôi đang hợp nhất các Bản đồ trong một vòng lặp for sử dụng một phương thức trả về một bản đồ và cần hợp nhất nó với một bản đồ khác và áp dụng cùng một phương thức agian. Đối với điều này, tôi nhận được ngoại lệ con trỏ null với phương thức putAll. nó không giúp sử dụng khối thử / bắt. tôi nên làm gì? Tôi đang áp dụng nếu có điều kiện, nếu kích thước == o thì không áp dụng put. Mọi người khác áp dụng nó và cứ thế ....
Mavin

1
Nếu bạn nhận được một NPE, thì rõ ràng bạn đã không khởi tạo một trong các đối tượng của mình đúng cách. Bạn có in stacktrace trong khối bắt không? Vì vậy, bạn biết nơi phát sinh vấn đề. Nhưng trừ khi bạn đăng mã đầy đủ và chính xác bao gồm cả dấu vết ngăn xếp, bạn sẽ cần tự mình theo dõi mã đó.
a_horse_with_no_name

94
Lưu ý rằng, với giải pháp này, nếu một khóa tồn tại trong cả hai bản đồ, giá trị trong map2 sẽ được giữ nguyên và giá trị trong map1 bị mất.
Michael Scheper

5
@MichaelScheper: bạn còn mong đợi gì nữa? Các khóa trong a Maplà theo định nghĩa duy nhất
a_horse_with_no_name 16/12/13

41
Tôi không biết những gì OPer mong đợi. Có thể anh ta hy vọng các giá trị map1 được ưu tiên hoặc một ngoại lệ được đưa ra hoặc cho một số hoạt động 'hợp nhất' được thực hiện trên các Số nguyên giao nhau. Hoặc có thể, vì đây là câu hỏi của người mới bắt đầu, đây là trường hợp mà OPer chưa xem xét, trong trường hợp đó, nhận xét của tôi hy vọng sẽ hữu ích.
Michael Scheper

109

Nếu bạn biết bạn không có khóa trùng lặp hoặc bạn muốn các giá trị map2ghi đè lên các giá trị từ map1các khóa trùng lặp, bạn chỉ cần viết

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

Nếu bạn cần kiểm soát nhiều hơn về cách kết hợp các giá trị, bạn có thể sử dụng Map.merge, được thêm vào trong Java 8, sử dụng do người dùng cung cấp BiFunctionđể hợp nhất các giá trị cho các khóa trùng lặp. mergehoạt động trên các khóa và giá trị riêng lẻ, vì vậy bạn sẽ cần sử dụng một vòng lặp hoặc Map.forEach. Ở đây chúng tôi nối các chuỗi cho các khóa trùng lặp:

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

Nếu bạn biết bạn không có khóa trùng lặp và muốn thực thi nó, bạn có thể sử dụng chức năng hợp nhất để ném AssertionError:

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

Lùi một bước từ câu hỏi cụ thể này, thư viện luồng Java 8 cung cấp toMapgroupingBy Bộ sưu tập . Nếu bạn liên tục hợp nhất các bản đồ trong một vòng lặp, bạn có thể cơ cấu lại tính toán của mình để sử dụng các luồng, điều này có thể làm rõ mã của bạn và cho phép xử lý song song dễ dàng bằng cách sử dụng một luồng song song và trình thu thập đồng thời.


46

Một lớp lót sử dụng API Java Stream 8:

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

Trong số các lợi ích của phương pháp này là khả năng vượt qua hàm hợp nhất, sẽ xử lý các giá trị có cùng khóa, ví dụ:

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

1
điều này sẽ ném IllegalStateException cho các khóa trùng lặp
Arpit J.

1
@ArpitJ. đó là toàn bộ điểm của biến thể thứ hai. Đôi khi bạn muốn ngoại lệ, đôi khi bạn không.
Alex R

36

Java 8 thay thế một lớp để hợp nhất hai bản đồ:

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

Tương tự với tham chiếu phương thức:

defaultMap.forEach(destMap::putIfAbsent);

Hoặc idemponent cho giải pháp bản đồ gốc với bản đồ thứ ba:

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

Và đây là một cách để hợp nhất hai bản đồ thành một bản đồ nhanh bất biến với Guava , hoạt động sao chép trung gian ít nhất có thể:

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

Xem thêm Hợp nhất hai bản đồ với Java 8 để biết các trường hợp khi các giá trị có trong cả hai bản đồ cần được kết hợp với chức năng ánh xạ.


32

Nếu bạn không cần khả năng biến đổi cho bản đồ cuối cùng của mình, thì có Guava ImmutableMap với phương thứcBuilderputAllphương thức của nó, trái ngược với phương thức giao diện của JavaMap , có thể bị xiềng xích.

Ví dụ sử dụng:

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

Tất nhiên, phương pháp này có thể chung chung hơn, sử dụng các biến và vòng lặp để putAll Mapstừ các đối số, v.v. nhưng tôi muốn hiển thị một khái niệm.

Ngoài ra, ImmutableMapvà nó Buildercó một vài hạn chế (hoặc có thể là các tính năng?):

  • chúng là null thù địch (ném NullPointerException- nếu bất kỳ khóa hoặc giá trị nào trong bản đồ là null)
  • Trình tạo không chấp nhận các khóa trùng lặp (ném IllegalArgumentExceptionnếu các khóa trùng lặp được thêm vào).



11

Giải pháp chung để kết hợp hai bản đồ có thể chia sẻ các khóa chung:

Tại chỗ:

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

Trả lại một bản đồ mới:

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

Một đoạn nhỏ tôi sử dụng rất thường xuyên để tạo bản đồ từ các bản đồ khác:

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

bạn có thể sử dụng HashMap<String, List<Integer>>để hợp nhất cả hai hashtag và tránh mất các phần tử được ghép nối với cùng một khóa.

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

đầu ra:

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

2

Rất muộn nhưng hãy để tôi chia sẻ những gì tôi đã làm khi tôi gặp vấn đề tương tự.

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

Nó cho đầu ra sau

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

Các mục trùng lặp sẽ không được thêm vào (đó là các khóa trùng lặp) vì khi chúng tôi in hs3, chúng tôi sẽ chỉ nhận được một giá trị cho khóa 5 sẽ là giá trị gia tăng cuối cùng và nó sẽ là chuột. ** [Set có thuộc tính không cho phép khóa trùng lặp nhưng giá trị có thể trùng lặp]


0

Phương pháp 1: Đặt bản đồ vào Danh sách và sau đó tham gia

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


}

Phương pháp 2: Hợp nhất bản đồ thông thường

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

Bạn có thể sử dụng hàm putAll cho Bản đồ như được giải thích trong mã bên dưới

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

Đoạn trích dưới đây có nhiều hơn một bản đồ và kết hợp chúng.

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

Liên kết ví dụ demo .


-1

bạn có thể sử dụng - phương thức addAll

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

Nhưng luôn có vấn đề này - nếu hai bản đồ băm của bạn có bất kỳ khóa nào giống nhau - thì nó sẽ ghi đè giá trị của khóa từ bản đồ băm đầu tiên bằng giá trị của khóa từ bản đồ băm thứ hai.

Để an toàn hơn - thay đổi các giá trị khóa - bạn có thể sử dụng tiền tố hoặc hậu tố trên các khóa - (tiền tố / hậu tố khác nhau cho bản đồ băm đầu tiên và tiền tố / hậu tố khác nhau cho bản đồ băm thứ hai)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.