İki set arasındaki farkın elde edilmesi


161

İki setim varsa:

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

Bunları karşılaştırmanın ve sadece 4 ve 5'lik bir setin iade edilmesinin bir yolu var mı?



11
Bu tam bir kopya değil: simetrik fark ve fark aynı değil.
Simon Nickerson

Eğer test1içerdiği 6, cevap 4,5,6 olurdu? yani simetrik farkı istiyor musunuz en.wikipedia.org/wiki/Symmetric_difference
Colin D

1
eğer test1 6 içeriyorsa, cevabın hala 4, 5 olmasını isterdim.
David Tunnell

Yanıtlar:


197

Bunu dene

test2.removeAll(test1);

Set # removeAll

Bu kümeden, belirtilen koleksiyonda bulunan tüm öğelerini kaldırır (isteğe bağlı işlem). Belirtilen koleksiyon da bir kümeyse, bu işlem bu kümesi etkin bir şekilde değiştirir, böylece değeri iki kümenin asimetrik küme farkı olur.


43
Bu işe yarayacaktır ama bence sendika, java'da fark gibi set operasyonlarının olması güzel bir özellik olacaktır. Yukarıdaki çözüm seti değiştirecektir, birçok durumda bunu gerçekten istemiyoruz.
Praveen Kumar

130
Java Bu veri yapısı a call zarar veriyorlarmış nasıl Seto tanımlamak vermediğinde union, intersectionya difference!!!
James Newman

10
Bu çözüm tam olarak doğru değil. Çünkü test1 ve test2'nin sırası bir fark yaratır.
Bojan Petkovic

1
Misiniz test1.removeAll(test2);aynı sonucu döndürür test2.removeAll(test1);?
datv

3
@datv Sonuç farklı olurdu. test1.removeAll(test2)boş bir kümedir. test2.removeAll(test1)olduğunu {4, 5}.
silentwf

122

Guava (eski Google Koleksiyonları) kitaplığını kullanıyorsanız bir çözüm vardır:

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

İade SetViewbir olduğunu Set, bu ya değişmez yapmak veya başka bir sete kopyalayabilirsiniz canlı temsilidir. test1ve test2bozulmadan kalır.


6
Not o sırayla dnm2 ve test1 konularda. Ayrıca , siparişin önemli olmadığı simetrikDifference () vardır .
datv

1
symmetricDifference()kavşak hariç hepsini getirecek, asıl sorunun sorduğu şey bu değil.
Allenaz

16

Evet:

test2.removeAll(test1)

Bu değişmesine rağmen test2, korumanız gerekiyorsa bir kopya oluşturun.

Ayrıca, muhtemelen <Integer>bunun yerine demek istediniz <int>.


7

Java 8

Biz yararlanabilirler removeIf olarak bir yardımcı yöntem yazmanın bir yüklem alır:

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

Ve hala önceki bir sürümdeyse, removeAll'ı şu şekilde kullanabiliriz:

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

Java 8 kullanıyorsanız, böyle bir şey deneyebilirsiniz:

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: Belki de diğer cevapların hangisinin Setdaha büyük olduğunu kontrol etmediğini fark edemediniz ... Bu nedenle, aa'yı daha Setbüyük birinden çıkarmaya çalışıyorsanız Set, farklı sonuçlar alırsınız.
Josh M

40
bu fonksiyonun tüketicisinin daima küçük seti çıkarmak istediğini varsayıyorsunuz. Set farkı anti-değişimli ( en.wikipedia.org/wiki/Anticommutativity ). AB! = BA
Simon

7
Hangi fark varyantını uygularsanız public static <T> Set<T> difference(final Set<T> set1, final Set<T> set2) {uygula, imza olarak kullanırım , yöntem daha sonra genel yarar işlevi olarak kullanılabilir.
kap

1
@kap ancak daha sonra Comparator<T>karşılaştırmayı özelleştirebilmek için a ekleyin çünkü equalsher zaman yeterli değildir.
gervais.b

6
Fark işleminin sırası kullanıcının farkında olmadan değiştirilebileceği için bu beklenmedik sonuçlara yol açacaktır. Daha büyük bir setin daha küçük bir setten çıkarılması matematiksel olarak iyi tanımlanmıştır ve bunun için birçok kullanım durumu vardır.
Joel Cornett

3

İlk koleksiyondaki CollectionUtils.disjunctiontüm farklılıkları veya farkı elde etmek için kullanabilirsiniz CollectionUtils.subtract.

İşte bunun nasıl yapılacağına dair bir örnek:

    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
Hangi projeden CollectionUtilsgeliyor? 1'in bunun Apache Commons Collection'dan olduğunu varsayması gerekiyor mu?
Buhake Sindi

0

Sadece burada (sistem olduğunu bir örnek koymak existingStateve biz (uzaklaştırmak için olmayan unsurları unsurları bulmak istiyorum newStateama mevcut existingStateolan (elemanlarını eklemek için) ve elementler newStateancak mevcut değildir 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);

  }
}

sonuç olarak çıktı:

Elements to add : [0, 99, 11]
Elements to remove : [1, 4]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.