두 세트의 차이 얻기


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 세트 만 반환하는 방법이 있습니까?



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
이것은 작동하지만 Java와 같은 union, union과 같은 집합 연산을 갖는 것이 좋은 기능이라고 생각합니다. 위의 솔루션은 많은 경우에 실제로 세트를 수정하지 않을 것입니다.
Praveen Kumar

129
자바는이 데이터 구조 a를 호출하는 담즙이 어떻게 Set그것을 정의하지 않는 경우 union, intersection또는 difference!
James Newman

10
이 솔루션은 완전하지 않습니다. test1과 test2의 순서가 달라지기 때문입니다.
보얀 페트코비치

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

반환 값 SetViewSet입니다. 변경 불가능하거나 다른 세트로 복사 할 수있는 라이브 표현입니다. test1그리고 test2그대로 남아 있습니다.


6
test2 및 test1 의 순서 가 중요합니다. 순서가 중요하지 않은 symmetricDifference () 도 있습니다 .
datv

1
symmetricDifference()교차점을 제외한 모든 것을 가져올 것입니다. 원래의 질문이 아닙니다.
Allenaz

16

예:

test2.removeAll(test1)

이 기능은 변경되지만 test2보존해야 할 경우 사본을 만듭니다.

또한, 당신은 아마 <Integer>대신에 의미 했습니다 <int>.


7

자바 8

removeIf 를 사용 하여 유틸리티 메소드를 작성하는 술어를 다음과 같이 사용할 수 있습니다.

// 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
해당 함수의 소비자는 항상 더 작은 세트를 빼기를 원한다고 가정합니다. 차이를 설정하는 것은 반 소통입니다 ( 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 그러나 항상 충분하지는 Comparator<T>않기 때문에 비교를 사용자 정의 할 수 있도록 a 를 추가하십시오 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.