147

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

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

特定の属性に基づいて、list1の要素がlist2に存在するかどうかを確認したいと思います(Object1とObject2には(とりわけ)、attributeSameという名前の1つの相互属性(タイプLong)があります)。

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

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

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

ありがとう!

4

11 に答える 11

269

基本的な等価性をテストする必要がある場合は、基本的な JDK を使用して、入力リストを 1 行で変更することなく実行できます。

!Collections.disjoint(list1, list2);

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

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

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

于 2012-08-03T15:59:46.040 に答える
49

Apache Commons CollectionUtilsを使用できます。

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

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

于 2012-08-03T13:19:17.423 に答える
10

名前付きの方法が 1 つありますが、参照用にいくつかの副作用がありますCollectionretainAll

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

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

そのような

boolean b = list1.retainAll(list2);
于 2012-08-03T13:23:17.163 に答える
6

ロイウスの答えは正しいです。例を追加したいだけです:

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
于 2016-02-19T16:57:07.827 に答える
2

より速くするために、ブレークを追加できます。そうすれば、found が 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 つのマップでより速く確認できます。

于 2012-08-03T13:10:17.843 に答える
2

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

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

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

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

于 2012-08-03T13:13:00.070 に答える
2

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

例えば:

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

  2. 他のリストを調べて、HashSet に項目があるかどうかを確認します。

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

于 2012-08-03T13:20:21.570 に答える
0

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
于 2018-02-13T07:04:40.830 に答える
0

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

たとえば、データが大きく、並べ替えられていない場合は、インデックスによって 2 つのリストを一緒に反復処理し、各リスト属性を別のリスト ヘルパーに格納することができます。次に、ヘルパー リストの現在の属性でクロス チェックできます。

幸運を

編集済み : equals のオーバーロードはお勧めしません。それは危険であり、おそらくオブジェクトの意味に反します。

于 2012-08-03T13:27:39.560 に答える