对象 属性 的两个列表的交集

Intersection of two lists by object property

如果我有两个对象列表,我可以找到交集如下:

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());

有没有类似的方法根据MyObjectid字段求交集?我无法重写 equals 方法。

是:

List<MyObject> intersect =
    list1.stream()
         .filter(obj1 -> list2.stream().map(MyObject::getId).anyMatch(id -> id.equals(obj1.getId()))
         .collect(Collectors.toList());

当然,如果两个具有相同id的MyObject实例被认为是相同的,你可以实现一个equals方法,returns true当且仅当id是一样的,那你原码就够了。

你可以试试这个方法。但我认为这对性能没有好处:

List<MyObject> intersect = list1.stream()
                       .filter(l1 -> list2.stream().anyMatch(l2 -> l2.id.equals(l1.id)))
                       .collect(Collectors.toList());

与上面 Eran 的回答类似,但您可以先将 ID 拉出到一个单独的集合中,但效率可能稍高一些:

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 + 列表 2)

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());