Java 收集器 groupBy 对于某些键具有特殊行为

问题描述 投票:0回答:2

我有一个对象集合:

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

我需要按频道对其进行分组,即“RRF”或“其他”。但是,如果频道是“RRF”,我只能获得一个最小订单的标题。 所以预期的结果应该是:

{RRF=[Title 1], Other=[Title 4, Title 2]}

您有什么想法如何在一个流中做到这一点吗?

java java-stream collectors
2个回答
2
投票

您可以

groupBy
,并在下游使用
teeing
将流分成 2 部分 - 一个执行
minBy
,另一个执行
toList
。在合并参数中,您将检查标题并决定是否使用列表或最小元素。

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

这确实意味着所有内容,包括那些没有“RRF”标题的内容,都将被

minBy
'ed,这是您不需要进行的一些额外处理。

如果这是一个问题,我建议只

groupBy
,并从结果映射中删除非最小元素,或者根本不使用流。


0
投票

我相信你可以使用 Collector 得到你需要的东西

看看下面的代码。

Map<String,List<PdfTitleCustomizationDto>> result = dtoList.stream()
    .collect(Collectors.groupingBy(
        PdfTitleCustomizationDto::getChannel,
        Collectors.collectingAndThen(
            Collectors.minBy(Comparator.comparingInt(PdfTitleCustomizationDto::getOrder)),
            optionalDto - > optionalDto.map(Collections::singletonList).orElse(Collections.emptyList())
        )
    ));
© www.soinside.com 2019 - 2024. All rights reserved.