首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >将多个` `Collectors::groupBy`函数与Java Streams结合使用

将多个` `Collectors::groupBy`函数与Java Streams结合使用
EN

Stack Overflow用户
提问于 2018-05-28 18:05:49
回答 2查看 489关注 0票数 0

我遇到了一个问题,那就是如何正确地组合多个Collectors::groupingBy函数,然后将它们同时应用于给定的输入。

假设我有一些类实现了以下接口:

代码语言:javascript
运行
复制
interface Something {
    String get1();
    String get2();
    String get3();
    String get4();
}

现在我可以从这个接口获得一些方法组合的列表,即这些列表可以是:[Something::get1, Something::get3][Something::get2, Something::get1, Something::get3]

现在,有了这样一个方法列表和一些东西的列表,我想通过getter对这些东西进行分组。

我的意思是,例如,对于list [Something::get1, Something::get3]和list [Something1, Something2, ...],我希望获得先按get1然后按get2分组的列表。

这可以通过以下方式实现:

代码语言:javascript
运行
复制
var lst = List.of(smth1, smth2, smth3);
lst.stream()
   .collect(Collectors.groupingBy(Something::get1, Collectors.groupingBy(Something::get3)))

如果我想要应用于分组的任意方法列表,该怎么办?

我在想像这样的东西(ofc。这不起作用,但你会明白的):

假设List<Function<Something, String>> groupingFunctions是我们想要应用于分组的方法列表。

代码语言:javascript
运行
复制
var collector = groupingFunctions.stream()
                                 .reduce((f1, f2) -> Collectors.groupingBy(f1, Collectors.groupingBy(f2)))

然后

代码语言:javascript
运行
复制
List.of(smth1, smth2, smth3).stream().collect(collector)

但这种方法行不通。怎样才能达到我想要的结果?

EN

Stack Overflow用户

发布于 2018-05-28 20:04:50

因为您不知道列表中有多少个函数,所以不能声明一个反映嵌套的编译时类型。但是,即使使用一个产生未知结果类型的收集器类型,用你想要的干净的函数方式组合它也是不可行的。你能得到的最接近的是

代码语言:javascript
运行
复制
var collector = groupingFunctions.stream()
    .<Collector<Something,?,?>>reduce(
        Collectors.toList(),
        (c,f) -> Collectors.groupingBy(f, c),
        (c1,c2) -> { throw new UnsupportedOperationException("can't handle that"); });

这有两个基本问题。没有办法为两个Collector实例提供有效的合并功能,因此,虽然这可能适用于顺序操作,但它不是一个干净的解决方案。此外,结果映射的嵌套顺序将是相反的;列表的最后一个函数将提供最外层映射的键。

也许有方法可以解决这个问题,但所有这些方法都会使代码变得更加复杂。将其与直接循环进行比较:

代码语言:javascript
运行
复制
Collector<Something,?,?> collector = Collectors.toList();
for(var i = groupingFunctions.listIterator(groupingFunctions.size()); i.hasPrevious(); )
    collector = Collectors.groupingBy(i.previous(), collector);

您可以像这样使用收集器

代码语言:javascript
运行
复制
Object o = lst.stream().collect(collector);

,但是需要instanceof和类型转换来处理Map的…。

使用反映分组函数的List键创建一个单独的、非嵌套的Map会更简洁:

代码语言:javascript
运行
复制
Map<List<String>,List<Something>> map = lst.stream().collect(Collectors.groupingBy(
    o -> groupingFunctions.stream().map(f -> f.apply(o))
                          .collect(Collectors.toUnmodifiableList())));

它将允许查询像map.get(List.of(arguments, matching, grouping, functions))这样的条目

票数 0
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50563866

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档