【问题标题】:Intersection of two lists by object property对象属性的两个列表的交集
【发布时间】:2019-08-01 08:26:42
【问题描述】:
如果我有两个对象列表,我可以如下找到交集:
public class MyObject {
String id;
String someField;
String someOtherField;
}
List<MyObject> list1;
List<MyObject> list2;
List<MyObject> intersect = list1.stream()
.filter(list2::contains)
.collect(Collectors.toList());
有没有类似的方法可以根据MyObject的id字段找到交集?我无法覆盖 equals 方法。
【问题讨论】:
标签:
java
list
java-8
java-stream
intersection
【解决方案1】:
与上面 Eran 的回答类似,但可能效率更高一些,您可以先将 ID 提取到单独的 Set 中:
Set<String> ids = list2.stream().map(obj -> obj.id).collect(Collectors.toSet());
List<MyObject> intersect = list1.stream()
.filter(obj -> ids.contains(obj.id))
.collect(Collectors.toList());
这样做会更有效的原因是,对于list1 中的每个项目,您可以在 O(1) 时间内确定 ID 是否在 list2 中,因此总体而言,您的运行时间为 O(list1 + list2)
【解决方案2】:
是的:
List<MyObject> intersect =
list1.stream()
.filter(obj1 -> list2.stream().map(MyObject::getId).anyMatch(id -> id.equals(obj1.getId()))
.collect(Collectors.toList());
当然,如果两个具有相同 id 的 MyObject 实例被认为是相同的,您可以实现一个 equals 方法,当且仅当 id 相同时返回 true,然后您的原始代码就足够了.
【解决方案3】:
您可以尝试这种方法。但我认为这对性能没有好处:
List<MyObject> intersect = list1.stream()
.filter(l1 -> list2.stream().anyMatch(l2 -> l2.id.equals(l1.id)))
.collect(Collectors.toList());
【解决方案4】:
将ids 提取为Set,以便尽可能快地查找:
Set<String> inclusionsSet = list2.stream().map(a -> a.id()).collect(Collectors.toSet());
List<String> intersection = list1.stream().filter(a -> inclusionsSet.contains(a)).collect(Collectors.toList());