当前位置: 首页 > 知识库问答 >
问题:

使用reduce和collect查找平均值

敖毅
2023-03-14

我试图理解新的Java8流API。

http://docs.oracle.com/javase/tutorial/collections/streams/reduction.html

我找到了使用collect API查找数字平均值的示例。但我觉得,使用reduce()也可以做到这一点。

public class Test {

    public static void main(String[] args) {
        // Using collect
        System.out.println(Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
            .collect(Averager::new, Averager::accept, Averager::combine)
            .average());

        // Using reduce
        System.out.println(Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
            .reduce(new Averager(), (t, u) -> {
                t.accept(u);
                return t;
            }, (t, u) -> {
                t.combine(u);
                return t;
            }).average());
    }

    private static class Averager {
        private int total = 0;
        private int count = 0;

        public Averager() {
            // System.out.println("Creating averager");
        }

        public double average() {
            // System.out.println("Finding average");
            return count > 0 ? ((double) total) / count : 0;
        }

        public void accept(int i) {
            // System.out.println("Accepting " + i);
            total += i;
            count++;
        }

        public void combine(Averager other) {
            // System.out.println("Combining the averager : " + other);
            total += other.total;
            count += other.count;
        }

        @Override
        public String toString() {
            return "[total : " + total + ", count: " + count + "]";
        }
    }
}

共有1个答案

汤玉宸
2023-03-14

reducecollection之间的区别在于,collection是一种增强的约简形式,可以并行处理可变对象。collection算法对各种结果对象进行线程限制,这样即使它们不是线程安全的,也可以安全地进行更改。这就是averager使用collection工作的原因。对于使用reduce的顺序计算,这通常并不重要,但是对于并行计算,它将给出错误的结果,正如您所观察到的。

关键的一点是,reduce只要处理的是值,而不是可变对象,它就可以工作。您可以通过查看reduce的第一个参数来了解这一点。示例代码传递new Averager(),这是一个单个对象,在并行约简中多个线程将其用作标识值。并行流的工作方式是将工作负载拆分为由单个线程处理的段。如果多个线程正在突变同一个(非线程安全的)对象,那么应该清楚为什么这会导致不正确的结果。

可以使用reduce来计算平均值,但您需要使累加对象是不可变的。考虑对象immutableaverager:

static class ImmutableAverager {
    private final int total;
    private final int count;

    public ImmutableAverager() {
        this.total = 0;
        this.count = 0;
    }
    
    public ImmutableAverager(int total, int count) {
        this.total = total;
        this.count = count;
    }

    public double average() {
        return count > 0 ? ((double) total) / count : 0;
    }

    public ImmutableAverager accept(int i) {
        return new ImmutableAverager(total + i, count + 1);
    }

    public ImmutableAverager combine(ImmutableAverager other) {
        return new ImmutableAverager(total + other.total, count + other.count);
    }
}

注意,我调整了acceptcombine的签名,以返回一个新的immutableaverager而不是更改this。(这些更改还使方法与reduce的函数参数相匹配,因此我们可以使用方法引用。)您可以使用immutableaverager,如下所示:

    double average = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
            .parallel()
            .reduce(new ImmutableAverager(), 
                    ImmutableAverager::accept,
                    ImmutableAverager::combine)
            .average();
    System.out.println("Average: "+average);

reduce一起使用不可变值对象应该会并行地给出正确的结果。

最后,请注意,IntStreamDoubleStream具有SummaryStatistics()方法,而Collectors具有AveragingDoubleAveragingIntAveragingLong方法可以为您执行这些计算。然而,我认为问题更多的是关于收集和减少的机制,而不是关于如何最简洁地做平均。

 类似资料:
  • 我一直在寻找,没有找到一个简单的问题和答案堆栈溢出寻找一个数组的平均值。 这是我的阵列 我最初以为这个问题的答案是这样的: 然而,这给了我一个NaN的输出。 然后我尝试了这个: 这给了我68的输出。(我不知道为什么)。 所以我有两个问题。1。为什么我的输出是68?和2。有人能帮我找到数组的平均值吗?

  • 问题内容: 我必须在Python中找到列表的平均值。到目前为止,这是我的代码 我已经知道了,所以它可以将列表中的值相加,但是我不知道如何将其划分为它们? 问题答案: 在Python 3.4+上,你可以使用 statistics.mean() 在旧版本的Python上,你可以执行 在Python 2上,你需要转换len为浮点数才能进行浮点数除法 无需使用。它慢得多,并已在Python 3 中删除。

  • 我似乎无法从用户输入的分数中计算出平均分数。我也不能让它停止例外输入大于100或小于0。有人能告诉我我做错了什么吗?谢谢

  • 我正在尝试使用用户输入将数字放入一个数组,然后找到这些数字的平均值,也找到哪些数字大于平均值。这些数字进入一个数组,但当我试图求平均数时,我无法求出平均数,以及哪些数字大于平均数,因为对于试图求出大于平均数的数字的部分,并非所有变量都是可见的。但是,当我允许这个部分看到所有的变量(don't But{}围绕某些部分)时,它会找到每一个数的平均值。现在,它为每个数字打印平均值,而为大于平均值的数字打

  • 问题内容: 我正在尝试从数据集中返回总计/平均值行,其中包含某些字段的SUM和其他字段的AVG。 我可以通过以下方式在SQL中执行此操作: 我将其转换为SQLAlchemy的尝试如下: 但这是错误的: 问题答案: 您应该使用类似: 您不能在这里使用,因为SqlAlchemy试图找到一个将函数结果放入的字段,但是它失败了。