Spacejockey
Spacejockey

Reputation: 408

Intersection of two lists by object property

If I have two lists of objects, I can find the intersection as follows:

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

Is there a similar way to find the intersection based on the id field of MyObject? I can't override the equals method.

Upvotes: 2

Views: 3392

Answers (4)

Joshgun
Joshgun

Reputation: 432

You can try this approach. But I don't think it would be good for performance:

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

Upvotes: 3

Nicko
Nicko

Reputation: 659

Similarly to Eran's answer above but perhaps with slightly more efficiency you could pull the IDs out into a separate Set first:

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

The reason this would be more efficient is that for each item in list1 you can determine if the ID is in list2 in O(1) time so overally your runtime is O(list1 + list2)

Upvotes: 9

Prashant Pandey
Prashant Pandey

Reputation: 4682

Extract the ids to a Set, so that the lookups are as fast as possible:

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

Upvotes: 0

Eran
Eran

Reputation: 394156

Yes:

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

Of course, if two MyObject instances having the same id are considered identical, you can implement an equals method that returns true if and only if the ids are the same, and then your original code will suffice.

Upvotes: 3

Related Questions