检查一个列表是不是包含另一个列表中的元素
Posted
技术标签:
【中文标题】检查一个列表是不是包含另一个列表中的元素【英文标题】:Check if one list contains element from the other检查一个列表是否包含另一个列表中的元素 【发布时间】:2012-08-01 12:58:20 【问题描述】:我有两个列表,其中包含不同的对象。
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;
但我认为有更好更快的方法来做到这一点:) 有人可以提议吗?
谢谢!
【问题讨论】:
首先,当你设置 found = true;然后简单地打破;或者跳出循环 ***.com/questions/5187888/…。此外,为了快速搜索,请尝试使用二分搜索并更改您的 DS 以适应情况... 除了 Object 之外,它们是否共享一个共同的父级? @Woot4Moo 不,他们没有 【参考方案1】:如果你只需要测试基本相等,这可以用基本的JDK来完成,而无需修改一行中的输入列表
!Collections.disjoint(list1, list2);
如果您需要测试特定属性,那就更难了。我会推荐,默认情况下,
list1.stream()
.map(Object1::getProperty)
.anyMatch(
list2.stream()
.map(Object2::getProperty)
.collect(toSet())
::contains)
...收集list2
中的不同值并测试list1
中的每个值是否存在。
【讨论】:
这不会总是返回 false,因为它们都是 2 个不同的对象吗? 嗯,不是吗?如果两个集合之间没有对象 equals(),则进行不相交测试。 另外,请注意,对于列表,这将是 O(n*m);如果您愿意在比较之前将list1
复制到Set
中,您将得到O(n) + O(m),即O(n+m),代价是一些额外的RAM;这是在速度或内存之间进行选择的问题。
这仅适用于 "List为了缩短 Narendra 的逻辑,你可以使用这个:
boolean var = lis1.stream().anyMatch(element -> list2.contains(element));
【讨论】:
这个答案被低估了。 如果你愿意,可以再缩短一点:list1.stream().anyMatch(list2::contains);
【参考方案3】:
你可以使用Apache Commons CollectionUtils:
if(CollectionUtils.containsAny(list1,list2))
// do whatever you want
else
// do other thing
这假设您已经为您的自定义对象正确重载了 equals 功能。
【讨论】:
已经4年了,我也明确点出了包和功能。 当只有 jdk 的解决方案时,对 apache commons 投反对票 @ohcibi Java 也有一个内置的记录器,你应该去反对那些建议你使用 Log4j 和 Log4j2 的人。 @Woot4Moo 视情况而定。如果有理由使用 Log4j 来解决 OPs 问题,则没有理由反对。在这种情况下,apache commons 就像 99% 的建议 apache commons 的答案一样,只是无用的膨胀。 @ohcibi 但如果你已经在使用 Apache commons 那么它并不是真的臃肿。这是一个很好的答案。【参考方案4】:Collection
有一种方法,名为 retainAll
,但对您有一些副作用reference
仅保留此列表中包含在 指定的集合(可选操作)。换句话说,删除 从此列表中未包含的所有元素 指定的集合。
如果此列表因调用而改变,则为真
好像
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
【讨论】:
我想如果你将元素'A'添加到第二个列表 listTwo.add("A");即使 Collections.disjoint(listOne, listTwo);返回真。 如果 list.size 不相等怎么办?【参考方案6】:更快的方式需要额外的空间。
例如:
将一个列表中的所有项目放入一个HashSet(您必须自己实现哈希函数才能使用object.getAttributeSame())
遍历另一个列表并检查HashSet中是否有任何项目。
这样每个对象最多被访问一次。并且 HashSet 足够快,可以在 O(1) 中检查或插入任何对象。
【讨论】:
【参考方案7】:根据.contains(Object obj)
的JavaDoc:
如果此列表包含指定元素,则返回 true。更多的 正式地,当且仅当此列表包含至少一个时才返回 true 元素 e 使得 (o==null ? e==null : o.equals(e))。
因此,如果您为给定对象覆盖 .equals()
方法,您应该可以这样做:if(list1.contains(object2))...
如果元素是唯一的(即具有不同的属性),您可以覆盖.equals()
和.hashcode()
并将所有内容存储在HashSets
中。这将允许您检查一个是否在恒定时间内包含另一个元素。
【讨论】:
【参考方案8】:为了让它更快,你可以添加一个中断;这样,如果 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;
如果您将使用映射而不是列表作为键的属性相同,您可以更快地检查一个映射中的值,如果在第二个映射中存在对应的值。
【讨论】:
嗨,汤姆,感谢您的关注!是的,我在打字时忘记了“休息”。但我在想也许有一些算法,或者我应该将这些列表更改为其他集合。 没有比 O(n*m) 更好的东西了吗? .getAttributeSame() ? 没有提供Object1和Object2的getAttributeSame()方法的实现,也与问答无关;它只返回两个类都具有的属性(attributeSame,a Long)。【参考方案9】:你能定义你持有的数据类型吗?是大数据吗?排序了吗? 我认为您需要根据数据考虑不同的效率方法。
例如,如果您的数据很大且未排序,您可以尝试通过索引将两个列表一起迭代,并将每个列表属性存储在另一个列表助手中。 那么您可以通过帮助列表中的当前属性进行交叉检查。
祝你好运
已编辑:我不建议重载等于。它很危险,可能与您的对象 oop 含义相反。
【讨论】:
【参考方案10】: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
【讨论】:
【参考方案11】:使用 java 8
,我们可以像下面这样检查一个列表是否包含其他列表的任何元素
boolean var = lis1.stream().filter(element -> list2.contains(element)).findFirst().isPresent();
【讨论】:
以上是关于检查一个列表是不是包含另一个列表中的元素的主要内容,如果未能解决你的问题,请参考以下文章