【问题标题】:Collect averages Java Stream in one shot一次收集平均值 Java Stream
【发布时间】:2019-09-04 22:04:21
【问题描述】:

我正在尝试找到如何在一个衬里的对象列表中收集每个字段的平均值。

这是我要执行的操作:

public class Value {
  int a;
  int b;
  int c;
  // rest of the class
}

现在假设我有List<Value> values = getMillionValues();

我知道要获得一个领域的平均值,我可以执行以下操作:

int averageOfA = values.stream().mapToInt(Value::getA).average()

我需要做什么才能获得所有值的平均值,而上面的每个变量都没有重复行?

也许还有其他一些库,比如 Guava,可以帮助执行这些操作?

【问题讨论】:

  • 使用 for 循环。
  • 为每个字段创建一个新流可能比任何替代方案都便宜得多,这将涉及为每个值创建至少一个数组对象(最便宜的选项)。

标签: java list java-stream


【解决方案1】:

说真的,使用 for 循环。

int count = 0, sumA = 0, sumB = 0, sumC = 0;
for (Value v : values) {
    sumA += v.getA();
    sumB += v.getB();
    sumC += v.getC();
    count++;
}
double avgA = ((double) sumA) / count;
double avgB = ((double) sumB) / count;
double avgC = ((double) sumC) / count;

说真的,使用上面的代码。


虽然说你应该使用上面的代码,但你可以用流来做到这一点。
您需要一些价值持有者(平均值为 double,因此您的 Value 类无法存储平均值):

class AveragesResult {
    public final double a, b, c;
    public AveragesResult(double a, double b, double c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }
}
class AveragesIntermediate {
    public final double a, b;
    public AverageIntermediate(double a, double b) {
        this.a = a;
        this.b = b;
    }
}

现在我们已经完成了样板(为了更好地衡量,您应该实现hashCodeequalstoString,并添加一些getter),我们终于可以用简短而紧凑的方式编写流方式:

values.stream().collect(teeing(
   teeing(averagingInt​(Value::getA), averagingInt​(Value::getB), AveragesIntermediate::new),
          averagingInt(Value::getC),
          (ir, avgC) -> new AveragesResult(ir.a, ir.b, avgC));

这不是很难,对吧?确保您已静态导入所有 Collector 函数(所有这些 Collectors. 看起来更丑陋)并且您使用的是 Java 12(Collectors.teeing 是 Java 12 中的新功能)。

不要使用那个,使用一个很好的旧 for 循环。

【讨论】:

  • 但是,但是,但是……闪亮的流? (我完全同意使用 for 循环)。
  • 你可以做到。但我不推荐它。
  • 当你创建了AveragesResult 类后,你可以像values.stream().collect(AveragesResult::new, (ar, v) -> { ar.a += v.getA(); ar.b += v.getB(); ar.c += v.getC();} , (ar1,ar2) -> { ar1.a += ar2.a; ar1.b += ar2.b; ar1.c += ar2.c; }) 一样使用它。当您在 AveragesResult 类中创建 addmerge 方法时,它变得更具可读性。
  • 这会计算总和。您还需要跟踪计数(但您不需要结果中的计数),所以也许创建一个也包含计数字段的新类?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-10
  • 1970-01-01
  • 1970-01-01
  • 2021-12-22
  • 2019-08-14
  • 1970-01-01
相关资源
最近更新 更多