您可以创建一个函数,该函数采用任意数量的属性进行分组,并在循环中构造 - ,每次都将以前版本的自身作为收集器传递。groupingBy
Collector
downstream
public static <T> Map collectMany(List<T> data, Function<T, ?>... groupers) {
Iterator<Function<T, ?>> iter = Arrays.asList(groupers).iterator();
Collector collector = Collectors.groupingBy(iter.next());
while (iter.hasNext()) {
collector = Collectors.groupingBy(iter.next(), collector);
}
return (Map) data.stream().collect(collector);
}
请注意,函数的顺序是相反的,因此您必须以相反的顺序传递它们(或在函数内部反转它们,例如使用 或 Guava's ,无论您喜欢哪种)。grouper
Collections.reverse
Lists.reverse
Object groupedData = collectMany(data, Person::getTown, Person::getCountry, Person::getName);
或者像这样,使用老式循环来反转函数中的数组,即您不必以反序传递石斑鱼(但恕我直言,这更难理解):for
public static <T> Map collectMany(List<T> data, Function<T, ?>... groupers) {
Collector collector = Collectors.groupingBy(groupers[groupers.length-1]);
for (int i = groupers.length - 2; i >= 0; i--) {
collector = Collectors.groupingBy(groupers[i], collector);
}
return (Map) data.stream().collect(collector);
}
这两种方法都将返回 ,就像在原始代码中一样。根据您要对这些数据执行的操作,可能还值得考虑使用 Tunaki 建议的 。Map<?,Map<?,Map<?,T>>>
Map<List<?>,T>