2012-08-03 160 views
70

我有两个列表,其中有不同的对象。检查一个列表是否包含另一个列表中的元素

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

我要检查,如果从列表1元素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; 
} 

但我认为这是一个更好更快的方式来做到这一点:) 有人能提出呢?

谢谢!

+0

首先,当您设置found = true;然后简单地打破;或出来的循环 – Shubhansh 2012-08-03 13:10:42

+0

http://stackoverflow.com/questions/5187888/java-searching-within-a-list-of-objects。此外,为了迅速搜索尝试使用二进制搜索,并改变你的DS套件的情况... – Shubhansh 2012-08-03 13:13:14

+0

他们是否共享除了对象共同的父母? – Woot4Moo 2012-08-03 13:16:59

回答

143

这可以通过基本的JDK来完成,无需在一个行修改输入列表

!Collections.disjoint(list1, list2); 
+0

这不会总是返回false,因为它们都是2个不同的对象? – Venki 2014-02-19 15:02:13

+1

恩,不是吗?不相交的测试是否在两个集合之间没有对象equals()。 – 2014-02-19 16:15:56

+10

此外,请注意,对于列表,这将是O(n * m);如果你愿意在比较之前把'list1'复制到'Set'中,你将得到O(n)+ O(m),即O(n + m),代价是一些额外的RAM;这是在速度或内存之间进行选择的问题。 – 2016-03-01 13:10:21

1

为了让它更快,您可以添加一个中断;这样,如果发现被设置为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,你可以在一个地图检查值更快,如果有相应的在第二张地图中的价值还是没有。

+0

嗨,汤姆,谢谢你的注意!是的,我在打字时忘了“休息”。但我想也许有一些算法,或者我应该将这些列表更改为其他集合。 – Ned 2012-08-03 13:13:33

+0

我做了一个编辑回复你的评论 – Tom 2012-08-03 13:29:01

+0

没有比O(n * m)更好的东西吗? – Woot4Moo 2013-01-17 14:02:00

2

根据的JavaDoc为.contains(Object obj):如果此列表包含指定的元素,

返回true。更多 正式返回true,当且仅当此列表包含至少一个 元素e使得(o == null?e == null:o.equals(e))。

所以,如果你重写你的.equals()方法了给定的对象,你应该能够做到:if(list1.contains(object2))...

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

26

您可以使用Apache Commons CollectionUtils

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

这假定你已经正确重载了equals功能为您的自定义对象。

+0

死连线,队友。 – alexander 2016-02-15 13:22:28

+7

已经4年了,我也明确地说出了包和功能。 – Woot4Moo 2016-02-15 18:53:08

+0

当只有一个jdk解决方案时,用于apache commons的Downvote – ohcibi 2017-01-23 17:30:46

2

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

例如:

  1. 把所有项目都在一个列表到一个HashSet(你必须自己实现哈希函数使用object.getAttributeSame())

  2. 经过其他列表并检查是否有任何项目在HashSet中。

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

8

一个方法Collection命名retainAll但有一些副作用reference

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

如果此列表改变调用的结果

它像

boolean b = list1.retainAll(list2); 
0

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

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

祝你好运

编辑:我不会推荐重载等于。它的危险和可能违背你的对象oop的含义。

2

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 
+0

我想如果你添加元素'A'到第二个列表listTwo.add(“A”);即使Collections.disjoint(listOne,listTwo);返回true。 – 2017-06-28 20:56:58

相关问题