web-dev-qa-db-ja.com

1つのリストに他のリストの要素が含まれているかどうかを確認します

異なるオブジェクトを含む2つのリストがあります。

List<Object1> list1;
List<Object2> list2;

特定の属性に基づいて、list1の要素がlist2に存在するかどうかを確認します(Object1とObject2は(特に)、1つの相互属性(Long型)、attributeSameという名前を持っています)。

今、私はこのようにします:

boolean found = false;
for(Object1 object1 : list1){
   for(Object2 object2: list2){
       if(object1.getAttributeSame() == object2.getAttributeSame()){
           found = true;
           //also do something
       }
    }
    if(!found){
        //do something
    }
    found = false;
}

しかし、これを行うためのより良い、より速い方法があると思います:)誰かがそれを提案できますか?

ありがとう!

91
Ned

基本的な同等性をテストする必要がある場合、1行の入力リストを変更せずに基本的なJDKでこれを実行できます。

!Collections.disjoint(list1, list2);

特定のプロパティをテストする必要がある場合、それは難しくなります。デフォルトでは、

list1.stream()
   .map(Object1::getProperty)
   .anyMatch(
     list2.stream()
       .map(Object2::getProperty)
       .collect(toSet())
       ::contains)

...list2の個別の値を収集し、list1の各値の存在をテストします。

200
Louis Wasserman

Apache Commons CollectionUtils を使用できます。

if(CollectionUtils.containsAny(list1,list2)) {  
    // do whatever you want
} else { 
    // do other thing 
}  

これは、カスタムオブジェクトのequals機能が適切にオーバーロードされていることを前提としています。

35
Woot4Moo

1つのメソッドCollectionという名前のretainAllがありますが、いくつかの副作用があります 参照

指定されたコレクションに含まれるこのリスト内の要素のみを保持します(オプションの操作)。つまり、指定されたコレクションに含まれていない要素をすべてこのリストから削除します。

呼び出しの結果、このリストが変更された場合はtrue

そのような

boolean b = list1.retainAll(list2);
9
Harmeet Singh

ルイの答えは正しいです、例を追加したいだけです:

listOne.add("A");
listOne.add("B");
listOne.add("C");

listTwo.add("D");
listTwo.add("E");
listTwo.add("F");      

boolean noElementsInCommon = Collections.disjoint(listOne, listTwo); // true
5

ナレンドラのロジックを短縮するには、これを使用できます:

boolean var = lis1.stream().anyMatch(element -> list2.contains(element));
3
ketanjain

より高速な方法では、追加のスペースが必要になります。

例えば:

  1. 1つのリスト内のすべてのアイテムをHashSetに入れます(object.getAttributeSame()を使用するには、自分でハッシュ関数を実装する必要があります)

  2. 他のリストに目を通し、HashSetにアイテムがあるかどうかを確認します。

このようにして、各オブジェクトは最大で1回アクセスされます。また、HashSetはO(1)のオブジェクトをチェックまたは挿入するのに十分高速です。

2
lavin

より速くするために、ブレークを追加できます。そのように、見つかった場合にループは停止しますtrueに設定されます:

boolean found = false;
for(Object1 object1 : list1){
   for(Object2 object2: list2){
       if(object1.getAttributeSame() == object2.getAttributeSame()){
           found = true;
           //also do something  
           break;
       }
    }
    if(!found){
        //do something
    }
    found = false;
}

AttributeSameをキーとするリストの代わりにマップがある場合、2番目のマップに対応する値があるかどうかによって、1つのマップの値をより速くチェックできます。

2
Tom

.contains(Object obj) のJavaDocによると:

このリストに指定された要素が含まれている場合、trueを返します。より正式には、このリストに(o == null?e == null:o.equals(e))などの要素eが少なくとも1つ含まれている場合にのみtrueを返します。

したがって、指定したオブジェクトの.equals()メソッドをオーバーライドすると、次のことができるはずです:if(list1.contains(object2))...

要素が一意である(つまり、属性が異なる)場合は、.equals()および.hashcode()をオーバーライドして、すべてを HashSets に格納できます。これにより、一定時間内に別の要素が含まれているかどうかを確認できます。

2
npinti

org.springframework.util.CollectionUtils

boolean containsAny(Java.util.Collection<?> source, Java.util.Collection<?> candidates)

Return true if any element in 'candidates' is contained in 'source'; otherwise returns false
0
akjain

Java 8を使用すると、1つのリストに他のリストの要素が含まれているかどうかを以下のように確認できます

boolean var = lis1.stream().filter(element -> list2.contains(element)).findFirst().isPresent();
0
Narendra Jaggi

保持するデータのタイプを定義できますか?それはビッグデータですか?ソートされていますか?データに応じて異なる効率化アプローチを検討する必要があると思います。

たとえば、データが大きくソートされていない場合は、インデックスで2つのリストを繰り返し、各リスト属性を別のリストヘルパーに保存してみてください。次に、ヘルパーリストの現在の属性でクロスチェックできます。

幸運を

編集:そして私は等しいをオーバーロードすることはお勧めしません。それは危険であり、おそらくオブジェクトのoopの意味に反します。

0
R-E-L