Can i reduce the following code to one/two line?
DTO dto;
List<DTO> dtos;
List<Integer> list1 = dtos.stream().map(DTO::getFirstId).distinct().collect(Collectors.toList());
List<Integer> list2 = dtos.stream().map(DTO::getSecondId).distinct().collect(Collectors.toList());
List<Integer> reducedId = list1.stream().filter(list2::contains).collect(Collectors.toList());
Processing only Unique Elements using Stream distinct() and forEach() Since distinct() is a intermediate operation, we can use forEach() method with it to process only the unique elements.
You can use the Stream. distinct() method to remove duplicates from a Stream in Java 8 and beyond. The distinct() method behaves like a distinct clause of SQL, which eliminates duplicate rows from the result set.
Java 8 offers the possibility to create streams out of three primitive types: int, long and double. As Stream<T> is a generic interface, and there is no way to use primitives as a type parameter with generics, three new special interfaces were created: IntStream, LongStream, DoubleStream.
Using a single Java 8 stream is not a great choice here. Instead you should first create a Set so that you can perform an efficient contains test.
Set<Integer> secondIds = dtos.stream().map(DTO::getSecondId).collect(Collectors.toSet());
List<Integer> reducedIds = dtos.stream().map(DTO::getFirstId).distinct()
.filter(secondIds::contains).collect(Collectors.toList());
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With