2012-10-04 28 views
15

Tôi có hai bản đồ:Làm thế nào để nhận được sự khác biệt của bản đồ trong java?

Map<String, Object> map1; 
Map<String, Object> map2; 

Tôi cần nhận được sự khác biệt giữa các bản đồ này. Có tồn tại có thể apache utils làm thế nào để nhận được sự khác biệt này? Hiện tại, có vẻ như cần thiết lập mục nhập của từng bản đồ và tìm thấy diff1 = set1 - set2 và diff2 = set2- set1. Sau khi tạo bản đồ tóm tắt = diff1 + diff2 Trông rất lúng túng. Có tồn tại một cách khác? Cảm ơn.

Trả lời

33

Làm thế nào về google guava:

Maps.difference(map1,map2) 
+2

Cảm ơn. Tôi nghĩ về ổi, nhưng vì điều này cần giới thiệu thư viện mới trong dự án, bette không làm điều này. – user710818

+6

@ user710818 Bạn sẽ không hối tiếc - đó là một thư viện tuyệt vời – vitaly

+3

@ user710818 Bạn nên sử dụng nó trong dự án của bạn – Koerr

4
Set<Entry<String, Object>> diff = new HashSet<Entry<String, Object>>((map1.entrySet())); 
    diff.addAll(map2.entrySet());//Union 
    Set<Entry<String, Object>> tmp = new HashSet<Entry<String, Object>>((map1.entrySet())); 
    tmp.retainAll(map2.entrySet());//Intersection 
    diff.removeAll(tmp);//Diff 
+1

trả lời không giống chính xác. Map1 có thể chứa map2 hoặc map2 có thể chứa map1, hoặc bằng hoặc khác nhau theo bất kỳ hướng nào có thể tồn tại. – user710818

+0

@ user710818 Kiểm tra câu trả lời được cập nhật. –

2

Có một API MapDifference bởi Google Collections Library mà thấy nhiều phương pháp như:

boolean areEqual() 

trả về true nếu không có sự khác biệt giữa hai bản đồ; có nghĩa là, nếu các bản đồ bằng nhau.

Map<K,MapDifference.ValueDifference<V>> entriesDiffering() 

Trả về một khóa mô tả bản đồ không thể sửa đổi xuất hiện trong cả hai bản đồ, nhưng có giá trị khác nhau.

Map<K,V> entriesInCommon() 

Trả về bản đồ không thể sửa đổi có chứa các mục xuất hiện trong cả hai bản đồ; đó là, giao điểm của hai bản đồ.

5

Nếu tôi hiểu rõ bạn đang cố gắng tính symmetric difference giữa hai bộ bản đồ nhập.

Map<String, Object> map1; 
Map<String, Object> map2; 

Set<Entry<String, Object>> diff12 = new HashSet<Entry<String, Object>>(map1.entrySet()); 
Set<Entry<String, Object>> diff21 = new HashSet<Entry<String, Object>>(map2.entrySet()); 
Set<Entry<String, Object>> result; 

diff12.removeAll(map2.entrySet()); 
diff21.removeAll(map1.entrySet()); 
diff12.addAll(diff21); 

Xem xét hành vi khó xử mà bạn đã đề cập, chúng ta hãy xem xét kỹ hơn hành vi mã ở trên. Ví dụ, nếu chúng ta lấy ví dụ số từ liên kết đưa ra ở trên:

Map<String, Object> map1 = new HashMap<String, Object>(); 
map1.put("a", 1); 
map1.put("b", 2); 
map1.put("c", 3); 
map1.put("d", 4); 

Map<String, Object> map2 = new HashMap<String, Object>(); 
map2.put("a", 1);  
map2.put("d", 4); 
map2.put("e", 5); 

Sau khi tính toán sự khác biệt như hình, kết quả:

System.out.println(Arrays.deepToString(diff12.toArray())); 

cho:

[e=5, c=3, b=2] 

đó là kết quả chính xác. Nhưng, nếu chúng ta làm điều đó như thế này:

public class CustomInteger { 
    public int val; 

    public CustomInteger(int val) { 
     this.val = val; 
    } 

    @Override 
    public String toString() { 
     return String.valueOf(val); 
    }   
} 

map1.put("a", new CustomInteger(1)); 
map1.put("b", new CustomInteger(2)); 
map1.put("c", new CustomInteger(3)); 
map1.put("d", new CustomInteger(4)); 

map2.put("a", new CustomInteger(1));  
map2.put("d", new CustomInteger(4)); 
map2.put("e", new CustomInteger(5)); 

cùng một thuật toán cho kết quả như sau:

[e=5, a=1, d=4, d=4, b=2, a=1, c=3] 

mà không phải là chính xác (và có thể được mô tả như vụng về :))

Trong ví dụ đầu tiên bản đồ được điền với các giá trị int được tự động boxed đến các giá trị Integer.

The class Integer có triển khai riêng các phương pháp equalshashCode.

Lớp CustomInteger không triển khai các phương pháp này sao cho nó inherits chúng từ số Object class toàn diện.

API doc cho removeAll method từ Set interface nói như sau:

Xóa khỏi chế độ thiết lập này tất cả các yếu tố của nó được chứa trong bộ sưu tập quy định (hoạt động không bắt buộc). Nếu bộ sưu tập được chỉ định cũng là một tập hợp, hoạt động này có hiệu quả sửa đổi tập hợp này sao cho giá trị của nó là sự khác biệt thiết lập bất đối xứng của hai bộ.

Để xác định phần tử nào được chứa trong cả hai bộ sưu tập, phương thức removeAll sử dụng phương thức equals của phần tử thu thập.

Và đó là bắt: Phương thức equals của Integals trả về true nếu hai giá trị số giống nhau, trong khi phương thức equals của đối tượng sẽ trả về true nếu nó là cùng một đối tượng, ví dụ: :

Integer a = 1; //autoboxing 
Integer b = new Integer(1); 
Integer c = 2; 

a.equals(b); // true 
a.equals(c); // false 

CustomInteger d = new CustomInteger(1); 
CustomInteger e = new CustomInteger(1); 
CustomInteger f = new CustomInteger(2); 

d.equals(e); //false 
d.equals(f) // false 

d.val == e.val //true 
d.val == f.val //false 

Nếu nó vẫn còn một chút mờ tôi mạnh mẽ khuyên bạn nên đọc các hướng dẫn sau đây:

+0

câu trả lời ở trên đã thanh lịch hơn giải quyết các tính toán khác biệt! – linski

16

Dưới đây là một đoạn đơn giản, bạn có thể sử dụng thay vì thư viện ổi lớn:

public static <K, V> Map<K, V> mapDifference(Map<? extends K, ? extends V> left, Map<? extends K, ? extends V> right) { 
    Map<K, V> difference = new HashMap<>(); 
    difference.putAll(left); 
    difference.putAll(right); 
    difference.entrySet().removeAll(right.entrySet()); 
    return difference; 
} 

Check out the whole working example

1

xây dựng trên Vlad's example để làm việc với bản đồ của các kích cỡ khác nhau

public static <K, V> Map<K, V> mapDiff(Map<? extends K, ? extends V> left, Map<? extends K, ? extends V> right) { 
     Map<K, V> difference = new HashMap<>(); 
     difference.putAll(left); 
     difference.putAll(right); 

     difference.entrySet().removeAll(left.size() <= right.size() ? left.entrySet() : right.entrySet()); 

     return difference; 
    } 
Các vấn đề liên quan