gpt4 book ai didi

Java 8 流 : groupingBy with multiple Collectors

转载 作者:搜寻专家 更新时间:2023-10-30 21:40:51 25 4
gpt4 key购买 nike

我想使用 Java 8 Stream 和 Group by one classifier 但有多个 Collector 函数。因此,在分组时,例如计算一个字段(或另一个字段)的平均值和总和。

我试着用一个例子来简化一下:

public void test() {
List<Person> persons = new ArrayList<>();
persons.add(new Person("Person One", 1, 18));
persons.add(new Person("Person Two", 1, 20));
persons.add(new Person("Person Three", 1, 30));
persons.add(new Person("Person Four", 2, 30));
persons.add(new Person("Person Five", 2, 29));
persons.add(new Person("Person Six", 3, 18));

Map<Integer, Data> result = persons.stream().collect(
groupingBy(person -> person.group, multiCollector)
);
}

class Person {
String name;
int group;
int age;

// Contructor, getter and setter
}

class Data {
long average;
long sum;

public Data(long average, long sum) {
this.average = average;
this.sum = sum;
}

// Getter and setter
}

结果应该是一个关联分组结果的Map,如

1 => Data(average(18, 20, 30), sum(18, 20, 30))
2 => Data(average(30, 29), sum(30, 29))
3 => ....

这对于像“Collectors.counting()”这样的一个函数非常有效,但我喜欢链接多个(理想情况下是列表中的无限)。

List<Collector<Person, ?, ?>>

有没有可能做这样的事情?

最佳答案

对于求和和平均的具体问题,使用collectingAndThen连同 summarizingDouble :

Map<Integer, Data> result = persons.stream().collect(
groupingBy(Person::getGroup,
collectingAndThen(summarizingDouble(Person::getAge),
dss -> new Data((long)dss.getAverage(), (long)dss.getSum()))));

对于更一般的问题(收集有关您的人员的各种信息),您可以像这样创建一个复杂的收集器:

// Individual collectors are defined here
List<Collector<Person, ?, ?>> collectors = Arrays.asList(
Collectors.averagingInt(Person::getAge),
Collectors.summingInt(Person::getAge));

@SuppressWarnings("unchecked")
Collector<Person, List<Object>, List<Object>> complexCollector = Collector.of(
() -> collectors.stream().map(Collector::supplier)
.map(Supplier::get).collect(toList()),
(list, e) -> IntStream.range(0, collectors.size()).forEach(
i -> ((BiConsumer<Object, Person>) collectors.get(i).accumulator()).accept(list.get(i), e)),
(l1, l2) -> {
IntStream.range(0, collectors.size()).forEach(
i -> l1.set(i, ((BinaryOperator<Object>) collectors.get(i).combiner()).apply(l1.get(i), l2.get(i))));
return l1;
},
list -> {
IntStream.range(0, collectors.size()).forEach(
i -> list.set(i, ((Function<Object, Object>)collectors.get(i).finisher()).apply(list.get(i))));
return list;
});

Map<Integer, List<Object>> result = persons.stream().collect(
groupingBy(Person::getGroup, complexCollector));

Map 值是列表,其中第一个元素是应用第一个收集器的结果,依此类推。您可以使用 Collectors.collectingAndThen(complexCollector, list -> ...) 添加自定义完成步骤,将此列表转换为更合适的列表。

关于Java 8 流 : groupingBy with multiple Collectors,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32071726/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com