Làm thế nào để đặt nội dung của Bản đồ băm trên Java của một thành một nội dung khác, nhưng không thay thế các khóa và giá trị hiện có?


83

Tôi cần sao chép tất cả các khóa và giá trị từ một HashMap A sang một HashMap khác B, nhưng không thể thay thế các khóa và giá trị hiện có.

Cách tốt nhất để làm điều đó là gì?

Thay vào đó, tôi đã nghĩ đến việc lặp lại keySet và checkig nếu nó tồn tại hay không, tôi sẽ

Map temp = new HashMap(); // generic later
temp.putAll(Amap);
A.clear();
A.putAll(Bmap);
A.putAll(temp);

Câu trả lời:


108

Có vẻ như bạn sẵn sàng tạo tạm thời Map, vì vậy tôi sẽ làm như thế này:

Map tmp = new HashMap(patch);
tmp.keySet().removeAll(target.keySet());
target.putAll(tmp);

Đây, patchlà bản đồ mà bạn đang thêm vào targetbản đồ.

Cảm ơn Louis Wasserman, đây là phiên bản tận dụng các phương thức mới trong Java 8:

patch.forEach(target::putIfAbsent);

Trong trường hợp này, bạn không cần phải làm removeAllvì dù sao thì chúng cũng sẽ bị ghi đè.
Reverend Gonzo

@Reverend Gonzo: Bị ghi đè bởi cái gì?
erickson

@luksmir Không, điều đó sẽ xóa các mục hiện có cần được giữ nguyên.
erickson

Chào! Tại sao mapWithValues.putAll (mapWithAosystemValues) không hoạt động?
betomoretti

15
@erickson một nhiều nhỏ gọn hơn phiên bản Java 8: patch.forEach(target::putIfAbsent).
Louis Wasserman

15

Sử dụng các phương thức tiện ích của lớp Bản đồ của Guava để tính toán sự khác biệt của 2 bản đồ, bạn có thể thực hiện điều đó trong một dòng duy nhất, với chữ ký phương thức giúp bạn hiểu rõ hơn những gì bạn đang cố gắng hoàn thành:

public static void main(final String[] args) {
    // Create some maps
    final Map<Integer, String> map1 = new HashMap<Integer, String>();
    map1.put(1, "Hello");
    map1.put(2, "There");
    final Map<Integer, String> map2 = new HashMap<Integer, String>();
    map2.put(2, "There");
    map2.put(3, "is");
    map2.put(4, "a");
    map2.put(5, "bird");

    // Add everything in map1 not in map2 to map2
    map2.putAll(Maps.difference(map1, map2).entriesOnlyOnLeft());
}

8

Chỉ cần lặp lại và thêm:

for(Map.Entry e : a.entrySet())
  if(!b.containsKey(e.getKey())
    b.put(e.getKey(), e.getValue());

Chỉnh sửa để thêm:

Nếu bạn có thể thực hiện các thay đổi đối với a, bạn cũng có thể thực hiện:

a.putAll(b)

và một ý chí có chính xác những gì bạn cần. (tất cả các mục trong bvà tất cả các mục akhông có trong b)


1.) entrySet()trả về a Set<Map.Entry>. 2.) Không có phương pháp nào contains(...)cho java.util.Map.
Fabian Barney

Không có cách nào thông minh hơn? Thích một tiện ích Bộ sưu tập hay như vậy? Tôi ghét tất cả các vòng lặp for ở khắp mọi nơi.
rapadura

1
@AntonioP: Tất cả các vòng lặp for ở khắp mọi nơi? Có một vòng lặp for và nó đơn giản nhất có thể.
Reverend Gonzo

+1 sau đó, chỉ hoạt động khi Maps được sử dụng không phải với loại thô, tôi nghĩ vậy. Bản thân tôi hơi bối rối với Bản đồ. Hãy thử :-)
Fabian Barney vào

@Reverend Gonzo, à, ở chỗ khác trong mã. :) Sẽ không .putAll thay thế các khóa và giá trị hiện có của a? Tôi đi với ý nghĩa này, nó có vẻ là cách đơn giản nhất.
rapadura

5

Bạn có thể thực hiện nó chỉ trong 1 dòng nếu bạn thay đổi thứ tự bản đồ trong giải pháp của @ erickson:

mapWithNotSoImportantValues.putAll( mapWithImportantValues );

Trong trường hợp này, bạn thay thế các giá trị trong mapWithNotSoImportantValues ​​bằng giá trị từ mapWithImportantValues ​​bằng các khóa tương tự.


2
public class MyMap {

public static void main(String[] args) {

    Map<String, String> map1 = new HashMap<String, String>();
    map1.put("key1", "value1");
    map1.put("key2", "value2");
    map1.put("key3", "value3");
    map1.put(null, null);

    Map<String, String> map2 = new HashMap<String, String>();
    map2.put("key4", "value4");
    map2.put("key5", "value5");
    map2.put("key6", "value6");
    map2.put("key3", "replaced-value-of-key3-in-map2");
    // used only if map1 can be changes/updates with the same keys present in map2.
    map1.putAll(map2);

    // use below if you are not supposed to modify the map1.
    for (Map.Entry e : map2.entrySet())
        if (!map1.containsKey(e.getKey()))
            map1.put(e.getKey().toString(), e.getValue().toString());
    System.out.println(map1);
}}

2

Với Java 8, có phương thức API này để thực hiện yêu cầu của bạn.

map.putIfAbsent(key, value)

Nếu khóa được chỉ định chưa được liên kết với một giá trị (hoặc được ánh xạ thành null) sẽ liên kết nó với giá trị đã cho và trả về giá trị null, thì khóa khác trả về giá trị hiện tại.


1
chúng ta có thể có putAllIfAbsent không? đó là những gì tôi cần?
user1735921

0

Như những người khác đã nói, bạn có thể sử dụng putIfAbsent. Lặp lại từng mục trong bản đồ mà bạn muốn chèn và gọi phương thức này trên bản đồ gốc:

mapToInsert.forEach(originalMap::putIfAbsent);
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.