Streamで2つの集計を同時に行う

個数と平均と合計、最大、最小を取るのであれば、標準でできます。

   IntSummaryStatistics iss = IntStream.of(2, 5, 7)
        .summaryStatistics();
   System.out.printf("%d %d %.1f%n", 
           iss.getCount(), iss.getSum(), iss.getAverage());


ただ、二乗和とかを取ろうと思うと、自分で畳込み処理をする必要があります。

    public static class Statistics{
        int squared;
        int total;
        int count;
    }

    Statisticsvs = IntStream.of(2, 5, 7).collect(
            () -> new Statistics(), 
            (v, i) -> {
                v.count++;
                v.total += i;
                v.squared += i * i;
            },
            (v, v2) -> {
                v.count += v2.count;
                v.total += v2.total;
                v.squared += v2.squared;
            } );
    System.out.printf("%d %d %d%n", 
        vs.count, vs.total, vs.squared);

collectoの第3引数は、結果同士の合成です。今の実装だとparallelではないときには使われないのだけど、ちゃんと実装しておいたほうがいいです。


あとは、これをCollectorとしておくと再利用しやすいです。

        Collector<Integer, Statistics, Statistics> coll = 
                Collector.of(
                        () -> new Statistics(), 
                (v, i) -> {
                    v.count++;
                    v.total += i;
                    v.squared += i * i;
                },
                (v, v2) -> {
                    Statistics ret = new Statistics();
                    ret.count = v.count + v2.count;
                    ret.total = v.total + v2.total;
                    ret.squared = v.squared + v2.squared;
                    return ret;
                });
        vs = IntStream.of(2, 5, 7).boxed().collect(coll);
        System.out.printf("%d %d %d%n", vs.count, vs.total, vs.squared);