检查一个列表是否包含另一个列表中的元素


105

我有两个带有不同对象的列表。

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

我想检查list2中的元素是否存在于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;
}

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

谢谢!


首先,当您设置found = true时;然后简单地休息;还是走出循环
jsist 2012年

stackoverflow.com/questions/5187888/…。此外,为了进行快速搜索,请尝试使用二进制搜索并更改您的DS以适应情况...
jsist 2012年

除了对象,他们共享一个共同的父母吗?
Woot4Moo 2012年

@ Woot4Moo不,他们不知道
Ned

Answers:


219

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

!Collections.disjoint(list1, list2);

如果您需要测试特定的属性,则难度更大。我建议默认情况下,

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

...收集不同的值list2并测试每个值list1是否存在。


1
因为两个都是2个不同的对象,这是否总是会返回false?
Venki 2014年

2
不?脱节测试两个集合之间是否没有对象equals()。
Louis Wasserman 2014年

13
另外,请注意,对于列表,该值为O(n * m);如果您愿意在比较之前将其复制list1到a中Set,则将获得O(n)+ O(m),即O(n + m),但需要一些额外的RAM;这是在速度还是内存之间进行选择的问题。
Haroldo_OK 2016年

仅当“ List <Person> list1; List <Person> list2”但不适用于两个不同的对象或数据类型(如List <Person> list1)时,此方法才有效。列表<员工>列表2。
whoami

当然,这不适用于@Zephyr的情况,对于所提出的问题,只要您实施了正确的对等方法,它就可以完美工作。这就是一切!
Syed Siraj Uddin

38

您可以使用Apache Commons CollectionUtils

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

假定您已经适当地重载了自定义对象的equals功能。


9
已有4年了,我还明确指出了程序包和功能。
Woot4Moo

1
当只有jdk解决方案时,请为Apache Commons下
票-ohcibi

9
@ohcibi Java也具有内置的记录器,您应该拒绝那些建议在使用Log4j和Log4j2时使用它的人。
Woot4Moo

1
@ Woot4Moo取决于。如果有理由使用Log4j解决OP问题,则没有理由不赞成投票。在这种情况下,就像在99%的建议apache commons的答案中一样,apache commons简直是无用的膨胀。
ohcibi

1
@ohcibi,但是如果您已经在使用Apache Commons,那么它并不是真的膨胀。这是一个很好的答案。
vab2048

19

要缩短Narendra的逻辑,可以使用以下命令:

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

3
这个答案被低估了。
Kervvv

您可以根据需要将其缩短一点:list1.stream().anyMatch(list2::contains);
tarka

9

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

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

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

就像是

boolean b = list1.retainAll(list2);

5

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

1
我想如果您将元素“ A”添加到第二个列表listTwo.add(“ A”); 即使Collections.disjoint(listOne,listTwo); 返回true。
Sairam Kukadala

2

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

例如:

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

  2. 浏览其他列表,检查HashSet中是否有任何项目。

这样,每个对象最多访问一次。HashSet的速度足以检查或在O(1)中插入任何对象。


2

根据JavaDoc的说明.contains(Object obj)

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

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

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


2

为了更快,您可以添加一个休息时间;这样,如果发现设置为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作为关键字的列表,则可以更快地检查一个地图中是否有值,如果第二个地图中没有对应的值。


汤姆,您好,感谢您的注意!是的,我在键入时忘记了“中断”。但是我在想也许有某种算法,或者我应该将这些列表更改为其他集合。
2012年

没有什么比O(n * m)好吗?
Woot4Moo

.getAttributeSame()?
行家ツ

没有提供Object1和Object2中方法getAttributeSame()的实现,但与问题和答案无关。它只是返回两个类都具有的属性(attributeSame,Long)。
汤姆(Tom)

0

您可以定义保存的数据类型吗?是大数据吗?它排序了吗?我认为您需要根据数据考虑不同的效率方法。

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

祝好运

编辑:我不建议重载等于。它很危险,并且可能违反您的对象oop的含义。



0

使用java 8,我们可以像下面一样检查一个列表是否包含其他列表的任何元素

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

0

如果要检查列表中是否存在元素,请使用contains方法。

if (list1.contains(Object o))
{
   //do this
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.