Den Unterschied zwischen zwei Sätzen ermitteln


160

Also, wenn ich zwei Sätze habe:

Set<Integer> test1 = new HashSet<Integer>();
test1.add(1);
test1.add(2);
test1.add(3);

Set<Integer> test2 = new HashSet<Integer>();
test2.add(1);
test2.add(2);
test2.add(3);
test2.add(4);
test2.add(5);

Gibt es eine Möglichkeit, sie zu vergleichen und nur einen Satz von 4 und 5 zurückzugeben?



11
Dies ist kein genaues Duplikat: Symmetrischer Unterschied und Unterschied sind nicht gleich.
Simon Nickerson

Wenn test1enthalten 6, wäre die Antwort 4,5,6? dh möchten Sie den symmetrischen Unterschied en.wikipedia.org/wiki/Symmetric_difference
Colin D

1
Wenn test1 6 enthält, möchte ich, dass die Antwort immer noch 4, 5 ist.
David Tunnell

Antworten:


197

Versuche dies

test2.removeAll(test1);

Setze # removeAll

Entfernt aus dieser Gruppe alle Elemente, die in der angegebenen Auflistung enthalten sind (optionale Operation). Wenn die angegebene Sammlung auch eine Menge ist, ändert diese Operation diese Menge effektiv so, dass ihr Wert die asymmetrische Mengendifferenz der beiden Mengen ist.


43
Dies wird funktionieren, aber ich denke, es wäre eine nette Funktion, die festgelegten Operationen wie Union, Differenz in Java zu haben. Die obige Lösung wird das Set modifizieren, in vielen Situationen wollen wir das nicht wirklich.
Praveen Kumar

129
Wie kann Java die Galle haben, diese Datenstruktur Setals a zu bezeichnen, wenn sie nicht definiert ist union, intersectionoder difference!!!
James Newman

10
Diese Lösung ist nicht vollständig korrekt. Weil die Reihenfolge von test1 und test2 einen Unterschied macht.
Bojan Petkovic

1
Würde test1.removeAll(test2);das gleiche Ergebnis zurückgeben wie test2.removeAll(test1);?
Datum

3
@datv Das Ergebnis wäre anders. test1.removeAll(test2)ist eine leere Menge. test2.removeAll(test1)ist {4, 5}.
Silentwf

122

Wenn Sie die Guava-Bibliothek (ehemals Google Collections) verwenden, gibt es eine Lösung:

SetView<Number> difference = com.google.common.collect.Sets.difference(test2, test1);

Die Rückgabe SetViewist eine SetLive-Darstellung, die Sie entweder unveränderlich machen oder in ein anderes Set kopieren können. test1und test2bleiben intakt.


6
Beachten Sie, dass die Reihenfolge von test2 und test1 von Bedeutung ist. Es gibt auch symmetricDifference (), bei dem die Reihenfolge keine Rolle spielt.
Datum

1
symmetricDifference()wird alle außer der Kreuzung bringen, das ist nicht das, was die ursprüngliche Frage gestellt hat.
Allenaz

16

Ja:

test2.removeAll(test1)

Obwohl dies mutiert test2, erstellen Sie eine Kopie, wenn Sie sie beibehalten müssen.

Außerdem meintest du wahrscheinlich <Integer>statt <int>.


7

Java 8

Wir können removeIf verwenden, das ein Prädikat verwendet, um eine Dienstprogrammmethode zu schreiben:

// computes the difference without modifying the sets
public static <T> Set<T> differenceJava8(final Set<T> setOne, final Set<T> setTwo) {
     Set<T> result = new HashSet<T>(setOne);
     result.removeIf(setTwo::contains);
     return result;
}

Und falls wir uns noch in einer früheren Version befinden, können wir removeAll wie folgt verwenden:

public static <T> Set<T> difference(final Set<T> setOne, final Set<T> setTwo) {
     Set<T> result = new HashSet<T>(setOne);
     result.removeAll(setTwo);
     return result;
}

3

Wenn Sie Java 8 verwenden, können Sie Folgendes versuchen:

public Set<Number> difference(final Set<Number> set1, final Set<Number> set2){
    final Set<Number> larger = set1.size() > set2.size() ? set1 : set2;
    final Set<Number> smaller = larger.equals(set1) ? set2 : set1;
    return larger.stream().filter(n -> !smaller.contains(n)).collect(Collectors.toSet());
}

4
@Downvoter: Vielleicht haben Sie nicht bemerkt, dass die anderen Antworten nicht prüfen, welche Setgrößer sind ... Wenn Sie also versuchen, eine kleinere Setvon einer größeren zu subtrahieren Set, erhalten Sie unterschiedliche Ergebnisse.
Josh M

40
Sie gehen davon aus, dass der Verbraucher dieser Funktion immer die kleinere Menge subtrahieren möchte. Der eingestellte Unterschied ist antikommutativ ( en.wikipedia.org/wiki/Anticommutativity ). AB! = BA
Simon

7
Unabhängig davon, welche Variante des Unterschieds Sie implementieren, würde ich public static <T> Set<T> difference(final Set<T> set1, final Set<T> set2) {als Signatur verwenden, die Methode kann dann als generische Dienstprogrammfunktion verwendet werden.
Kap

1
@kap aber füge dann ein hinzu Comparator<T>, um den Vergleich anpassen zu können, da dies equalsnicht immer ausreicht.
gervais.b

6
Dies führt zu unerwarteten Ergebnissen, da die Reihenfolge der Differenzoperation geändert werden kann, ohne dass der Benutzer dies bemerkt. Die Subtraktion einer größeren Menge von einer kleineren Menge ist mathematisch gut definiert und es gibt viele Anwendungsfälle dafür.
Joel Cornett

3

Sie können verwenden CollectionUtils.disjunction, um alle Unterschiede oder CollectionUtils.subtractden Unterschied in der ersten Sammlung zu erhalten.

Hier ist ein Beispiel dafür:

    var collection1 = List.of(1, 2, 3, 4, 5);
    var collection2 = List.of(2, 3, 5, 6);
    System.out.println(StringUtils.join(collection1, " , "));
    System.out.println(StringUtils.join(collection2, " , "));
    System.out.println(StringUtils.join(CollectionUtils.subtract(collection1, collection2), " , "));
    System.out.println(StringUtils.join(CollectionUtils.retainAll(collection1, collection2), " , "));
    System.out.println(StringUtils.join(CollectionUtils.collate(collection1, collection2), " , "));
    System.out.println(StringUtils.join(CollectionUtils.disjunction(collection1, collection2), " , "));
    System.out.println(StringUtils.join(CollectionUtils.intersection(collection1, collection2), " , "));
    System.out.println(StringUtils.join(CollectionUtils.union(collection1, collection2), " , "));

3
Aus welchem ​​Projekt kommt CollectionUtilsdas? Muss ich davon ausgehen, dass es aus der Apache Commons Collection stammt?
Buhake Sindi

0

existingStateUm nur ein Beispiel zu nennen (System ist in , und wir möchten Elemente zum Entfernen finden (Elemente, die nicht newStatevorhanden sind, aber vorhanden sind existingState) und Elemente zum Hinzufügen (Elemente, die vorhanden sind, newStateaber nicht vorhanden sind existingState):

public class AddAndRemove {

  static Set<Integer> existingState = Set.of(1,2,3,4,5);
  static Set<Integer> newState = Set.of(0,5,2,11,3,99);

  public static void main(String[] args) {

    Set<Integer> add = new HashSet<>(newState);
    add.removeAll(existingState);

    System.out.println("Elements to add : " + add);

    Set<Integer> remove = new HashSet<>(existingState);
    remove.removeAll(newState);

    System.out.println("Elements to remove : " + remove);

  }
}

würde dies als Ergebnis ausgeben:

Elements to add : [0, 99, 11]
Elements to remove : [1, 4]
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.