147

我有两个列表,其中包含不同的对象。

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

我想检查 list1 中的元素是否存在于 list2 中,基于特定属性(Object1 和 Object2 具有(除其他外),一个相互属性(类型为 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;
}

但我认为有更好更快的方法来做到这一点:) 有人可以提议吗?

谢谢!

4

11 回答 11

269

如果您只需要测试基本相等,可以使用基本JDK完成,而无需修改一行中的输入列表

!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 回答
57

为了缩短 Narendra 的逻辑,你可以使用这个:

boolean var = lis1.stream().anyMatch(element -> list2.contains(element));
于 2019-04-28T11:24:22.307 回答
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

有一种命名方法,但有一些副作用供您参考CollectionretainAll

仅保留此列表中包含在指定集合中的元素(可选操作)。换句话说,从这个列表中删除所有不包含在指定集合中的元素。

如果此列表因调用而更改,则为 true

就像是

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

Loius的回答是正确的,我只想补充一个例子:

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

如果您将使用映射而不是列表作为键属性相同,那么您可以更快地检查一个映射中的值,如果在第二个映射中有对应的值或没有相应的值。

于 2012-08-03T13:10:17.843 回答
2

根据 JavaDoc 的.contains(Object obj)

如果此列表包含指定元素,则返回 true。更正式地说,当且仅当此列表包含至少一个元素 e 满足 (o==null ? e==null : o.equals(e)) 时,才返回 true。

因此,如果您.equals()为给定对象覆盖您的方法,您应该能够:if(list1.contains(object2))...

如果元素是唯一的(即具有不同的属性),您可以覆盖.equals()and.hashcode()并将所有内容存储在 HashSets. 这将允许您检查一个是否在恒定时间内包含另一个元素。

于 2012-08-03T13:13:00.070 回答
2

更快的方式将需要额外的空间。

例如:

  1. 将一个列表中的所有项目放入一个 HashSet (您必须自己实现哈希函数才能使用 object.getAttributeSame() )

  2. 浏览另一个列表并检查 HashSet 中是否有任何项目。

这样每个对象最多被访问一次。并且 HashSet 足够快,可以在 O(1) 中检查或插入任何对象。

于 2012-08-03T13:20:21.570 回答
0

你能定义你持有的数据类型吗?是大数据吗?排序了吗?我认为您需要根据数据考虑不同的效率方法。

例如,如果您的数据很大且未排序,您可以尝试通过索引将两个列表一起迭代,并将每个列表属性存储在另一个列表助手中。然后您可以通过帮助列表中的当前属性进行交叉检查。

祝你好运

编辑:我不建议重载equals。它很危险,可能与您的对象 oop 含义相反。

于 2012-08-03T13:27:39.560 回答
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

有了java 8,我们可以像下面这样检查一个列表是否包含另一个列表的任何元素

boolean var = lis1.stream().filter(element -> list2.contains(element)).findFirst().isPresent();
于 2019-03-15T10:50:07.143 回答