รับความแตกต่างระหว่างสองชุด


161

ดังนั้นถ้าฉันมีสองชุด:

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

มีวิธีการเปรียบเทียบพวกเขาและมีเพียงชุดที่ 4 และ 5 กลับมา?


สำเนาซ้ำที่เป็นไปได้ของstackoverflow.com/questions/8064570/…
Sachin Thapa

11
สิ่งนี้ไม่ได้ซ้ำกันแน่นอน: ความแตกต่างแบบสมมาตรและความแตกต่างไม่เหมือนกัน
Simon Nickerson

ถ้าtest1มี6คำตอบจะเป็น 4,5,6 หรือไม่ เช่นคุณต้องการความแตกต่างแบบสมมาตรen.wikipedia.org/wiki/Symmetric_difference
Colin D

1
ถ้า test1 มี 6 ฉันต้องการคำตอบที่ยังคงเป็น 4, 5
David Tunnell

คำตอบ:


197

ลองสิ่งนี้

test2.removeAll(test1);

ชุด # removeAll

ลบออกจากชุดนี้องค์ประกอบทั้งหมดที่มีอยู่ในคอลเลกชันที่ระบุ (การดำเนินการเสริม) หากคอลเลกชันที่ระบุเป็นชุดการดำเนินการนี้จะแก้ไขชุดนี้อย่างมีประสิทธิภาพเพื่อให้ค่าของมันคือความแตกต่างของชุดอสมมาตรของทั้งสองชุด


43
สิ่งนี้จะใช้งานได้ แต่ฉันคิดว่ามันจะเป็นคุณสมบัติที่ดีที่มีการตั้งค่าการดำเนินงานเช่นยูเนี่ยนความแตกต่างในจาวา ทางออกข้างต้นจะแก้ไขชุดในหลาย ๆ สถานการณ์ที่เราไม่ต้องการ
Praveen Kumar

129
วิธี Java สามารถมีถุงน้ำดีที่จะเรียกโครงสร้างข้อมูลนี้Setเมื่อมันไม่ได้กำหนดunion, intersectionหรือdifference!!!
James Newman

10
วิธีนี้ไม่ถูกต้องอย่างสมบูรณ์ เพราะคำสั่งของ test1 และ test2 สร้างความแตกต่าง
Bojan Petkovic

1
จะtest1.removeAll(test2);ให้ผลลัพธ์เหมือนกันtest2.removeAll(test1);หรือไม่
datv

3
@datv ผลลัพธ์จะแตกต่างกัน test1.removeAll(test2)เป็นชุดที่ว่างเปล่า เป็นtest2.removeAll(test1) {4, 5}
silentwf

122

หากคุณใช้ห้องสมุด Guava (อดีต Google Collections) มีวิธีแก้ไข:

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

การคืนค่าSetViewคือSet, มันคือการแสดงสดที่คุณสามารถทำให้ไม่เปลี่ยนรูปหรือคัดลอกไปยังชุดอื่น test1และtest2เหลืออยู่เหมือนเดิม


6
โปรดสังเกตว่าลำดับของ test2 และ test1 มีความสำคัญ นอกจากนี้ยังมีsymmetricDifference ()ซึ่งคำสั่งนั้นไม่สำคัญ
datv

1
symmetricDifference()จะนำมาซึ่งทั้งหมดยกเว้นจุดตัดไม่ใช่คำถามเดิมที่ถาม
Allenaz

16

ใช่:

test2.removeAll(test1)

แม้ว่าสิ่งนี้จะกลายพันธุ์test2ดังนั้นโปรดสร้างสำเนาหากคุณต้องการเก็บไว้

นอกจากนี้คุณอาจจะมีความหมายแทน<Integer><int>


7

Java 8

เราสามารถใช้remove ถ้าซึ่งใช้เพรดิเคตเพื่อเขียนวิธีอรรถประโยชน์เป็น:

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

และในกรณีที่เรายังอยู่ในเวอร์ชันก่อนหน้าเราสามารถใช้ removeAll เป็น:

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 คุณสามารถลองดังนี้:

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: บางทีคุณล้มเหลวที่จะรู้ว่าคำตอบอื่น ๆ ไม่ได้ตรวจสอบเพื่อดูว่าSetมีขนาดใหญ่กว่า ... ดังนั้นหากคุณพยายามที่จะลบขนาดเล็กลงSetจากขนาดใหญ่กว่าSetคุณจะได้รับผลลัพธ์ที่แตกต่างกัน
Josh M

40
คุณสมมติว่าผู้บริโภคของฟังก์ชั่นนั้นต้องการลบชุดที่เล็กกว่าเสมอ ชุดที่แตกต่างคือ anticommutative ( en.wikipedia.org/wiki/Anticommutativity ) AB! = BA
Simon

7
ไม่ว่าคุณจะใช้ความแตกต่างใดฉันจะใช้public static <T> Set<T> difference(final Set<T> set1, final Set<T> set2) {เป็นลายเซ็นวิธีการนั้นจึงสามารถใช้งานได้เป็นฟังก์ชั่นยูทิลิตี้ทั่วไป
kap

1
@kap แต่เพิ่ม a Comparator<T>เพื่อให้สามารถปรับแต่งการเปรียบเทียบได้เนื่องจากequalsไม่เพียงพอเสมอ
gervais.b

6
สิ่งนี้จะนำไปสู่ผลลัพธ์ที่ไม่คาดคิดเนื่องจากอาจมีการสลับลำดับการดำเนินการที่แตกต่างกันโดยที่ผู้ใช้ไม่ได้รับรู้ การลบชุดที่มีขนาดใหญ่กว่าจากชุดที่เล็กกว่านั้นมีความชัดเจนทางคณิตศาสตร์และมีกรณีการใช้งานมากมาย
Joel Cornett

3

คุณสามารถใช้CollectionUtils.disjunctionเพื่อรับความแตกต่างทั้งหมดหรือCollectionUtils.subtractเพื่อให้ได้ความแตกต่างในคอลเล็กชันแรก

นี่คือตัวอย่างของวิธีการทำ:

    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
โครงการใดCollectionUtilsมาจากไหน 1 ต้องคิดว่ามันมาจาก Apache Commons Collection หรือไม่?
Buhake Sindi

0

เพียงแค่ใส่ตัวอย่างหนึ่งที่นี่ (ระบบอยู่ในexistingStateและเราต้องการที่จะหาองค์ประกอบที่จะลบ (องค์ประกอบที่ไม่ได้อยู่ในnewStateแต่มีอยู่ในexistingState) และองค์ประกอบที่จะเพิ่ม (องค์ประกอบที่อยู่ในnewStateแต่ไม่ได้อยู่ใน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);

  }
}

จะเอาท์พุทนี้เป็นผล:

Elements to add : [0, 99, 11]
Elements to remove : [1, 4]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.