Mendapatkan perbedaan antara dua set


161

Jadi jika saya memiliki dua set:

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

Apakah ada cara untuk membandingkan mereka dan hanya memiliki set 4 dan 5 yang dikembalikan?



11
Ini bukan duplikat yang tepat: perbedaan dan perbedaan simetris tidak sama.
Simon Nickerson

Jika test1ada 6, apakah jawabannya 4,5,6? yaitu Anda ingin perbedaan simetris en.wikipedia.org/wiki/Symmetric_difference
Colin D

1
jika test1 berisi 6, saya ingin jawabannya tetap 4, 5.
David Tunnell

Jawaban:


197

Coba ini

test2.removeAll(test1);

Setel # removeAll

Menghapus dari set ini semua elemennya yang terkandung dalam koleksi yang ditentukan (operasi opsional). Jika koleksi yang ditentukan juga merupakan himpunan, operasi ini secara efektif memodifikasi himpunan ini sehingga nilainya adalah perbedaan himpunan asimetris dari dua himpunan.


43
Ini akan bekerja tetapi saya pikir itu akan menjadi fitur yang bagus untuk memiliki operasi seperti serikat, perbedaan dibangun di java. Solusi di atas akan mengubah set, dalam banyak situasi kita tidak benar-benar menginginkannya.
Praveen Kumar

130
Bagaimana Java memiliki empedu untuk memanggil struktur data ini Setketika tidak didefinisikan union, intersectionatau difference!!!
James Newman

10
Solusi ini tidak sepenuhnya benar. Karena urutan test1 dan test2 membuat perbedaan.
Bojan Petkovic

1
Akan test1.removeAll(test2);mengembalikan hasil yang sama test2.removeAll(test1);?
datv

3
@datv Hasilnya akan berbeda. test1.removeAll(test2)adalah set kosong. test2.removeAll(test1)adalah {4, 5}.
silentwf

122

Jika Anda menggunakan perpustakaan Guava (sebelumnya Google Collections) ada solusinya:

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

Yang dikembalikan SetViewadalah Set, itu adalah representasi langsung yang bisa Anda buat tidak berubah atau menyalin ke set lain. test1dan test2dibiarkan utuh.


6
Perhatikan bahwa urutan test2 dan test1 penting. Ada juga symmetricDifference () di mana urutannya tidak masalah.
datv

1
symmetricDifference()akan membawa semua kecuali persimpangan, bukan itu pertanyaan aslinya.
Allenaz

16

Iya:

test2.removeAll(test1)

Meskipun ini akan bermutasi test2, jadi buat salinan jika Anda perlu melestarikannya.

Juga, Anda mungkin bermaksud <Integer>bukannya <int>.


7

Java 8

Kita dapat menggunakan removeIf yang memerlukan predikat untuk menulis metode utilitas sebagai:

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

Dan jika kita masih di beberapa versi sebelumnya maka kita dapat menggunakan removeAll sebagai:

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

Jika Anda menggunakan Java 8, Anda dapat mencoba sesuatu seperti ini:

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: Mungkin Anda gagal menyadari bahwa jawaban lain tidak memeriksa untuk melihat mana Setyang lebih besar ... Oleh karena itu, jika Anda mencoba mengurangi aa yang lebih kecil Setdari yang lebih besar Set, Anda akan menerima hasil yang berbeda.
Josh M

40
Anda berasumsi bahwa konsumen fungsi itu selalu ingin mengurangi set yang lebih kecil. Setel anticommutative ( en.wikipedia.org/wiki/Anticommutativity ). AB! = BA
Simon

7
Terlepas dari varian perbedaan yang Anda terapkan, saya akan menggunakan public static <T> Set<T> difference(final Set<T> set1, final Set<T> set2) {sebagai tanda tangan, metode ini kemudian dapat digunakan sebagai fungsi utilitas umum.
kap

1
@kap tetapi kemudian tambahkan Comparator<T>untuk dapat menyesuaikan perbandingan karena equalstidak selalu cukup.
gervais.b

6
Ini akan menghasilkan hasil yang tidak terduga karena urutan operasi perbedaan dapat dialihkan tanpa pengguna sadari. Pengurangan satu set yang lebih besar dari set yang lebih kecil secara matematis didefinisikan dengan baik dan ada banyak kasus penggunaan untuk itu.
Joel Cornett

3

Anda dapat menggunakan CollectionUtils.disjunctionuntuk mendapatkan semua perbedaan atau CollectionUtils.subtractuntuk mendapatkan perbedaan dalam koleksi pertama.

Berikut ini contoh cara melakukannya:

    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
Dari mana proyek itu CollectionUtilsberasal? Apakah saya harus berasumsi bahwa itu dari Apache Commons Collection?
Buhake Sindi

0

Hanya dengan memberikan satu contoh di sini (sistem dalam existingState, dan kami ingin menemukan elemen untuk dihapus (elemen yang tidak ada newStatetetapi ada existingState) dan elemen untuk ditambahkan (elemen yang ada newStatetetapi tidak ada 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);

  }
}

akan menampilkan ini sebagai hasilnya:

Elements to add : [0, 99, 11]
Elements to remove : [1, 4]
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.