I have a collection of objects:
List<PdfTitleCustomizationDto> dtoList = Arrays.asList(
new PdfTitleCustomizationDto("Title 1", 1, "RRF", Set.of(new Role("ADMIN"))),
new PdfTitleCustomizationDto("Title 2", 2, "Other", Set.of(new Role("USER"))),
new PdfTitleCustomizationDto("Title 3", 3, "RRF", Set.of(new Role("ADMIN"))),
new PdfTitleCustomizationDto("Title 4", 4, "Other", Set.of(new Role("ADMIN")))
);
I need to group it by channel, which is "RRF" or "Other. However, if channel is "RRF", I have to get only one title with min order. So the expected result should be:
{RRF=[Title 1], Other=[Title 4, Title 2]}
Do you have any ideas how to do it in one stream?
You can groupBy
, and in the downstream, use teeing
to split the stream into 2 - one does minBy
, the other does toList
. In the merger argument, you would check the title and decide whether to use the list, or the minimum element.
var y = list.stream().collect(
Collectors.groupingBy(
PdfTitleCustomizationDto::getChannel,
Collectors.teeing(
Collectors.minBy(Comparator.comparing(PdfTitleCustomizationDto::getTitle)),
Collectors.toList(),
(min, list) -> min
.filter(x -> "RRF".equals(x.getTitle()))
.map(List::of)
.orElse(list)
)
)
);
This does mean that everything, including those without the "RRF" title, will be minBy
'ed, which is some extra processing that you wouldn't need to do otherwise.
If that is a problem, I recommend just groupBy
, and remove the non-min elements from the resulting map, or just don't use streams at all.