Javaセットの「何かを含む」のような何か?


307

同じタイプのAとBの2つのセットがあります。

AにセットBの要素が含まれているかどうかを確認する必要があります。

セットを反復せずにそれを行うための最良の方法は何でしょうか?Setライブラリにはcontains(object)およびcontainsAll(collection)がありcontainsAny(collection)ますが、ありません。


4
効率上の理由から、またはコードのクリーンさのために反復を回避しようとしていますか?
yshavit 2012年

回答:


527

うまくいきませんCollections.disjoint(A, B)か?ドキュメントから:

true指定された2つのコレクションに共通の要素がない場合に返します。

したがって、falseコレクションに共通の要素が含まれている場合、メソッドは戻ります。


17
セットを変更したり、新しいセットを作成したりしないため、これを他のソリューションよりも優先してください。
devconsole 2012

7
標準のJREであり、設定されているだけでなく、任意のコレクションで動作します。
Pierre Henry

4
これは最も高速だとは思いません。交差点の最初の要素が見つかったときに短絡しません。
ベンホーナー2016

7
実際には、最初の共通要素が検出されるとすぐに短絡します
Xipo


156

Stream::anyMatch

Java 8以降は使用できますStream::anyMatch

setA.stream().anyMatch(setB::contains)

1
これがまさに私が探していたものです!ありがとう:-) ::構文で変数を使用できることも知りませんでした!
dantiston

1
@ blevert、anyMatch内で何が起こるかを説明できますか?
クリスティアーノ

8
ここの@Cristianoは、anyMatchすべての要素をストリーミングし、それらすべてをsetA呼び出しsetB.contains()ます。いずれかの要素に対して「true」が返された場合、式は全体としてtrueと評価されます。これがお役に立てば幸いです。
Alex Vulaj 16


31

セットにcontainsAnyを実装する良い方法は、Guava Sets.intersection()を使用することです。

containsAnyはを返すbooleanため、呼び出しは次のようになります。

Sets.intersection(set1, set2).isEmpty()

セットがばらばらであればtrueを返し、そうでなければfalseを返します。元のセットを変更しないようにするためにクローンを作成する必要がないため、この時間の複雑さはおそらくretainAllよりもわずかに優れています。


3
この方法を使用する唯一の欠点は、グアバライブラリを含める必要があることです。googleコレクションAPIは非常に強力であるため、これは不利ではないと思います。
Mohammad Adnan 2014年

@DidierLこれを含むほとんどのGuavaコレクションユーティリティ関数は、データ構造のビューを返します。したがって、この場合に心配する「セットの構築」はありません。実装はここで読むのは興味深いです、および/またはJavadocを参照してください。google.github.io/guava/releases/21.0/api/docs/com/google/common/...
chut

@MohammadAdnanもう1つの欠点は、完全な交差を計算することです。set1とset2が非常に大きい場合、共通の項目があるかどうかを確認するよりも(CPUとメモリの両方で)かなり多くのリソースを消費します。
Marxama


16

私はorg.apache.commons.collections.CollectionUtilsを使用しています

CollectionUtils.containsAny(someCollection1, someCollection2)

以上です!少なくとも1つの要素が両方のコレクションにある場合、trueを 返します。

使い方は簡単で、関数の名前はより暗示的です。


5

retainAll()Setインターフェースで使用します。このメソッドは、両方のセットに共通する要素の共通部分を提供します。詳細については、APIドキュメントを参照してください。


反復を回避する目的が効率のためである場合、retainAllおそらく役に立たないでしょう。AbstractCollection反復でのその実装。
yshavit

1
yshavitは正しいです。OPが両方のセットに要素が存在するかどうを確認している場合、適切なアルゴリズムはO(1)、最良の場合には実行時間retainAllを持ちますが、ラインに沿って何かを持ちますO(N)(1つのセットのサイズに依存します)。最高の実行時間。
Zéychin

3

私が作成お勧めHashMapセットAから、セットBを反復し、Bのいずれかの要素がA.これにあるかどうかをチェックすることで実行されることになるO(|A|+|B|)(非衝突がないように)時間、一方retainAll(Collection<?> c)で必須の実行O(|A|*|B|)時間。


3

それを行うには少し大雑把な方法があります。Aセットに呼び出しよりもBの要素が含まれている場合に限り

A.removeAll(B)

Aセットを変更します。この状況では、removeAllはtrueを返します(removeAll docsで述べたとおり)。しかし、おそらくAセットを変更したくないので、次のようにコピーを操作することを考えます。

new HashSet(A).removeAll(B)

また、セットが明確でない場合、つまり空でない交差がある場合、戻り値はtrueになります。

Apache Commons Collectionも参照してください


2

RetainAllメソッドを使用して、2つのセットの共通部分を取得できます。


ほとんどの場合、元のセットを保持する必要があるため、使用retainAllするには元のセットのコピーを作成する必要があります。その後HashSetZéychinの提案に従って使用するとより効率的です
PetrPudlák2012

これは、状態変化ではなく、条件チェックだ
ベン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.