You may force it into one stream operation, but the performance would be even worse than what you have now, i.e. an operation with quadratic time complexity.
A better approach would be:
Set<Integer> set = dtos.stream().map(DTO::getSecondId).collect(Collectors.toSet());
List<Integer> result = dtos.stream().map(DTO::getFirstId)
.distinct().filter(set::contains).collect(Collectors.toList());
// result now contains the common IDs
By collecting the second IDs into a Set
instead of a List
, you don’t need to use distinct()
in the first stream operation and avoid the linear search applied to every element in the second stream operation when contains
is invoked.
You may generally consider using a Set
for remembering unique IDs. When using a Set
as result type, you may avoid the distinct()
of the second stream operation too:
Set<Integer> set = dtos.stream().map(DTO::getSecondId).collect(Collectors.toSet());
Set<Integer> result = dtos.stream().map(DTO::getFirstId)
.filter(set::contains).collect(Collectors.toSet());
If you suspect lots of duplicate IDs and want to keep the behavior of sorting out duplicates before checking the other Set
, you may use:
Set<Integer> set = dtos.stream().map(DTO::getSecondId).collect(Collectors.toSet());
Set<Integer> result = dtos.stream().map(DTO::getFirstId)
.collect(Collectors.toCollection(HashSet::new));
result.retainAll(set);
Note that if you prefer long, hard too read “one liner”, you can inline the set
variable in all variants.