Reputation: 408
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
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
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
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
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