Java 8 Stream: groupingBy with multiple Collectors

后端 未结 4 752
野性不改
野性不改 2020-12-15 08:20

I want to use a Java 8 Stream and Group by one classifier but have multiple Collector functions. So when grouping, for example the average and the sum of one field (or maybe

4条回答
  •  不思量自难忘°
    2020-12-15 09:11

    For the concrete problem of summing and averaging, use collectingAndThen along with summarizingDouble:

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

    For the more generic problem (collect various things about your Persons), you can create a complex collector like this:

    // Individual collectors are defined here
    List> collectors = Arrays.asList(
            Collectors.averagingInt(Person::getAge),
            Collectors.summingInt(Person::getAge));
    
    @SuppressWarnings("unchecked")
    Collector, List> complexCollector = Collector.of(
        () -> collectors.stream().map(Collector::supplier)
            .map(Supplier::get).collect(toList()),
        (list, e) -> IntStream.range(0, collectors.size()).forEach(
            i -> ((BiConsumer) collectors.get(i).accumulator()).accept(list.get(i), e)),
        (l1, l2) -> {
            IntStream.range(0, collectors.size()).forEach(
                i -> l1.set(i, ((BinaryOperator) 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)collectors.get(i).finisher()).apply(list.get(i))));
            return list;
        });
    
    Map> result = persons.stream().collect(
            groupingBy(Person::getGroup, complexCollector)); 
    
    
    

    Map values are lists where first element is the result of applying the first collector and so on. You can add a custom finisher step using Collectors.collectingAndThen(complexCollector, list -> ...) to convert this list to something more appropriate.

    提交回复
    热议问题