2012-10-04 14 views
15

Ich habe zwei Karten:Wie bekomme ich den unterschied der karten in java?

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

I Unterschied zwischen diesen Karten erhalten müssen. Gibt es Apache utils wie man diese Differenz erhält? Für jetzt scheint brauchen Eintragsmenge jeder Karte zu nehmen und gefunden diff1 = set1 - set2 und diff2 = set2 - set1. Nach erstellen Übersichtskarte = diff1 + diff2 Es sieht sehr umständlich. Gibt es einen anderen Weg? Danke.

Antwort

33

Wie wäre es google guava:

Maps.difference(map1,map2) 
+2

Danke. Ich habe über Guave nachgedacht, aber dafür muss ich eine neue Bibliothek in das Projekt einführen, aber machen Sie das nicht. – user710818

+6

@ user710818 Sie würden es nicht bereuen - es ist eine großartige Bibliothek – vitaly

+3

@ user710818 Sie sollten es in Ihrem Projekt verwenden – 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

Antwort nicht richtig funktioniert aussehen. Map1 könnte map2 enthalten oder map2 könnte map1 enthalten oder gleich sein oder es könnte eine Differenz in irgendeiner Richtung existieren. – user710818

+0

@ user710818 Überprüfen Sie die aktualisierte Antwort. –

2

Es gibt eine MapDifference API von Google Collections Library, die Methoden wie aussetzt:

boolean areEqual() 

Gibt true zurück, wenn es keine Unterschiede zwischen den beiden Karten; Das heißt, wenn die Karten gleich sind.

Gibt eine nicht änderbare Map zurück, die Schlüssel beschreibt, die in beiden Maps mit unterschiedlichen Werten angezeigt werden.

Map<K,V> entriesInCommon() 

Gibt eine nicht änderbare Karte zurück, die die Einträge enthält, die in beiden Karten erscheinen; das heißt, der Schnittpunkt der beiden Karten.

5

Wenn ich gut verstanden habe, versuchen Sie symmetric difference zwischen den beiden Karteneintragsmengen zu berechnen.

In Anbetracht des umständlichen Verhaltens, das Sie erwähnt haben, wollen wir uns das obige Codeverhalten genauer ansehen. Zum Beispiel, wenn wir das Zahlenbeispiel aus dem oben angegebenen Link nehmen:

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

Nachdem Sie den Unterschied, wie gezeigt, die Ausgabe zu berechnen:

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

gibt:

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

das ist das richtige Ergebnis Aber wenn wir es tun, wie folgt:

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

der gleiche Algorithmus gibt die folgende Ausgabe:

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

, die nicht korrekt ist (und könnte genauso umständlich :) beschrieben)

In Im ersten Beispiel wird die Map mit int-Werten gefüllt, die automatisch boxed zu Integer-Werten sind.

The class Integer hat eine eigene Implementierung von equals und hashCode Methoden.

Die Klasse CustomInteger implementiert diese Methoden nicht, so dass sie inherits sie aus dem omnipräsent Object class.

Die API doc für die removeAll method vom Set interface sagt der folgende:

aus dieser Menge alle Elemente entfernt, die (optional Betrieb) in der angegebenen Auflistung enthalten sind. Wenn die angegebene Auflistung ebenfalls eine Menge ist, ändert diese Operation diese Menge effektiv, so dass ihr Wert die asymmetrische Mengenabweichung der zwei Mengen ist.

Um zu bestimmen, welche Elemente in beiden Sammlungen enthalten sind, verwendet die Methode removeAll das Gleichheits Verfahren des Sammelelements.

Und das ist der Haken: Integer ist gleich Methode true zurück, wenn die beiden numerischen Werte gleich sind, während Objekts gleich wird Methode true zurück, nur, wenn es die gleiche Objekt, z.B. :

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 

Wenn ich die folgenden Tutorials stark noch ein wenig unscharf ist schlagen Lesen:

+0

Die obige Antwort hat die Differenzberechnung eleganter gelöst! – linski

16

Hier ist ein einfaches Snippet Sie statt verwenden können massive Guava-Bibliothek:

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

Aufbauend auf Vlad's example mit Karten verschiedener Größen

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