2つのセットの違いを取得する


161

したがって、2つのセットがある場合:

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 2013

test1含まれている場合6、答えは4,5,6になりますか?つまり、対称的な差分が必要ですかen.wikipedia.org/wiki/Symmetric_difference
Colin D

1
test1のは、6が含まれている場合、私は5、答えはまだ4になりたい
デヴィッドTunnellの

回答:


197

これを試して

test2.removeAll(test1);

Set#removeAll

このセットから、指定されたコレクションに含まれるすべての要素を削除します(オプションの操作)。指定したコレクションもセットである場合、この操作はこのセットを効果的に変更して、その値が2つのセットの非対称セットの差になるようにします。


43
これは機能しますが、Javaに組み込まれているunionのようなset演算があると便利な機能だと思います。上記のソリューションはsetを変更しますが、多くの場合、私たちはそれを望んでいません。
Praveen Kumar 14

129
Set定義されていないときにJavaがこのデータ構造を呼び出すゴールをどのように持つことができますかunionintersectionまたはdifference!!!
James Newman

10
このソリューションは完全に正しくはありません。test1とtest2の順序が異なるためです。
Bojan Petkovic 2016年

1
test1.removeAll(test2);同じ結果を返しtest2.removeAll(test1);ますか?
datv 2017

3
@datv結果は異なります。test1.removeAll(test2)空のセットです。test2.removeAll(test1)です{4, 5}
silentwf 2017

122

Guava(以前のGoogleコレクション)ライブラリを使用する場合、解決策があります。

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

次のようにユーティリティメソッドを記述するための述語を取る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) {シグネチャとして使用し、メソッドは汎用ユーティリティ関数として使用できます。
2016年

1
@kapですが、常に十分ではないComparator<T>ため、比較をカスタマイズできるようにを追加しequalsます。
gervais.b 2016

6
これにより、ユーザーが気づかないうちに差分演算の順序が入れ替わる可能性があるため、予期しない結果が生じます。小さいセットから大きいセットを減算することは数学的に明確に定義されており、その使用例はたくさんあります。
Joel Cornett、2016

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からのものであると想定する必要がありますか?
ブハケシンディ

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.