将多个`Collectors::groupBy`函数与Java流组合
我在正确组合多个将多个`Collectors::groupBy`函数与Java流组合,java,java-stream,collectors,Java,Java Stream,Collectors,我在正确组合多个收集器::groupingBy函数,然后将它们同时应用于给定输入时遇到问题 假设我有一个类实现了以下接口: interface Something { String get1(); String get2(); String get3(); String get4(); } 现在我可以从这个界面得到一些方法组合的列表,也就是说,这些列表可以是: [Something::get1,Something::get3],[Something::get2,
收集器::groupingBy
函数,然后将它们同时应用于给定输入时遇到问题
假设我有一个类实现了以下接口:
interface Something {
String get1();
String get2();
String get3();
String get4();
}
现在我可以从这个界面得到一些方法组合的列表,也就是说,这些列表可以是:
[Something::get1,Something::get3]
,[Something::get2,Something::get1,Something::get3]
现在,有了这样一个方法列表和一些东西列表,我想通过getter对这些东西进行分组
我的意思是,例如,对于列表[Something::get1,Something::get3]
和列表[Something1,Something2,…]
我想得到一些东西的列表,首先按get1
分组,然后按get2
分组
这可以通过以下方式实现:
var lst = List.of(smth1, smth2, smth3);
lst.stream()
.collect(Collectors.groupingBy(Something::get1, Collectors.groupingBy(Something::get3)))
如果我有任意的方法列表要应用于分组,该怎么办
我在想这样的事情(ofc。这不起作用,但你会明白的):
假设List groupingFunctions
是我们要应用于分组的方法列表
var collector = groupingFunctions.stream()
.reduce((f1, f2) -> Collectors.groupingBy(f1, Collectors.groupingBy(f2)))
然后
List.of(smth1, smth2, smth3).stream().collect(collector)
但这种方法行不通。如何实现我所想的结果?您可以这样做:
public static Collector createCollector(Function<A, String>... groupKeys) {
Collector collector = Collectors.toList();
for (int i = groupKeys.length - 1; i >= 0; i--) {
collector = Collectors.groupingBy(groupKeys[i], collector);
}
return collector;
}
您可以像这样使用此收集器
:
Object result = somethingList.stream().collect(collector);
因为您知道传递给收集器的groupingBy
数量,所以可以将其转换为相应的Map
结果。在这种情况下,将应用两个groupingBy
:
Map<String, Map<String, List<Something>>> mapResult = (Map<String, Map<String, List<Something>>>) result
Map mapResult=(映射)结果
由于不知道列表中有多少函数,因此不能声明反映嵌套的编译时类型。但是,即使使用一个收集器类型生成一些未知的结果类型,组合它也不能以您想要的干净函数方式解决。你能得到的最接近的是
var collector = groupingFunctions.stream()
.<Collector<Something,?,?>>reduce(
Collectors.toList(),
(c,f) -> Collectors.groupingBy(f, c),
(c1,c2) -> { throw new UnsupportedOperationException("can't handle that"); });
您可以像这样使用收集器
Object o = lst.stream().collect(collector);
但是需要instanceof
并键入cast来处理Map
s
使用反映分组功能的列表
键创建一个非嵌套的映射
会更简洁:
Map<List<String>,List<Something>> map = lst.stream().collect(Collectors.groupingBy(
o -> groupingFunctions.stream().map(f -> f.apply(o))
.collect(Collectors.toUnmodifiableList())));
Map Map=lst.stream().collect(Collectors.groupingBy(
o->groupingFunctions.stream().map(f->f.apply(o))
.collect(Collectors.toUnmodifiableList());
它将允许查询诸如
map.get(List.of(参数、匹配、分组、函数))
最终结果是什么样子的?最终结果是一个嵌套的映射。最终map
键值类型是4嵌套的,可以原始类型吗?如何使用结果,当你不知道它的类型时?@Holger-如果某个东西有一个属性<代码>列表子对象和一个属性<代码>字符串名称,我会将映射重新映射到某个对象,其中键是名称,列表是子对象,这样就不会有问题了。我只是想有一个通用的解决方案来创建一个深度嵌套的树状结构。实际上,我不能强制转换它,因为我不知道将应用多少groupingBy。它可以是1、2、5或任何其他数量的分组。另外,我想坚持函数方法,这就是我提到reduce的原因。我知道我可以循环查看函数列表,但我不想这样做。您可以使用functional
方法重构createCollector
。但是没有什么能解决这个问题。最后,您仍然需要知道铸造的Map
类型
Object o = lst.stream().collect(collector);
Map<List<String>,List<Something>> map = lst.stream().collect(Collectors.groupingBy(
o -> groupingFunctions.stream().map(f -> f.apply(o))
.collect(Collectors.toUnmodifiableList())));