如何使用 Java8 流获取多属性的平均值?



有一个对象

@Data
class ScoreInfo{
String id;
float cove_score;
float theam_score;
float content_score;
float teach_score;
Date create_date;
ScoreInfoP scoreInfoP;

}

而ScoreInfoP是:

@Data
class ScoreInfoP{
String stream_sn;
String anchor_id;
String create_by;
}

sourceList是ScoreInfo的列表,我想获取cove_score,theam_score,content_score,teach_score的平均值,按scoreInfoP属性分组并为每个属性返回四个平均值。

我只能使用以下代码获得一个平均值:

Map<ScoreInfoP, Double> meanForCoveScore = sourceList.stream().collect(Collectors.groupingBy(ScoreInfo::getScoreInfoP,
Collectors.averagingDouble(ScoreInfo::getCove_score)));

我想学习如何使用 java8 或您建议实现此目的的任何更简单的方法获得四个平均值。

在这里等待您的慷慨帮助。

没有任何内置功能,但为此构建自定义收集器并不复杂......

Map<String, List<Float>> result = Arrays.asList(first, second)
.stream()
.collect(Collectors.groupingBy(
x -> x.getScoreInfoP().getAnchorId(), 
Collector.of(
() -> new float[5],
(a, x) -> {
a[0] += x.getCoveScore();
a[1] += x.getTheamScore();
a[2] += x.getTeachScore();
a[3] += x.getContentScore();
a[4]++;
},
(left, right) -> {
for (int i = 0; i < 4; ++i) {
left[i] += right[i];
}
return left;
}, x -> Arrays.asList(x[0] / x[4], x[1] / x[4], x[2] / x[4], x[3] / x[4]))
));
System.out.println(result);

我实际上在ScoreInfoP#anchorId上分组了这里; 但你可以在ScoreInfoP上做到这一点 - 为此你需要将x -> x.getScoreInfoP().getAnchorId()更改为x -> x.getScoreInfoP()。但显然ScoreInfoP需要覆盖hashCodeequals.

正如我在评论中所说,您应该使用适当的结果类。

class ScoreInfoAverage {
private float cove_score;
private float theam_score;
private float content_score;
private float teach_score;
// ctor, getter, setter
}

然后,您可以使用自定义Collector

public static Collector<ScoreInfo, ?, ScoreInfoAverage> scoreInfoToAverage() {
class ScoreInfoAccumulator {
private DoubleSummaryStatistics cove_score = new DoubleSummaryStatistics();
private DoubleSummaryStatistics theam_score = new DoubleSummaryStatistics();
private DoubleSummaryStatistics content_score = new DoubleSummaryStatistics();
private DoubleSummaryStatistics teach_score = new DoubleSummaryStatistics();
public void add(ScoreInfo si) {
cove_score.accept(si.cove_score);
theam_score.accept(si.theam_score);
content_score.accept(si.content_score);
teach_score.accept(si.teach_score);
}
public ScoreInfoAccumulator combine(ScoreInfoAccumulator sia) {
cove_score.combine(sia.cove_score);
theam_score.combine(sia.theam_score);
content_score.combine(sia.content_score);
teach_score.combine(sia.teach_score);
return this;
}
public ScoreInfoAverage average() {
return new ScoreInfoAverage((float) cove_score.getAverage(), 
(float) theam_score.getAverage(), (float) content_score.getAverage(), 
(float) teach_score.getAverage());
}
}
return Collector.of(ScoreInfoAccumulator::new, ScoreInfoAccumulator::add, 
ScoreInfoAccumulator::combine, ScoreInfoAccumulator::average);
}

最后但并非最不重要的一点是,您将Collector添加到下游:

Map<ScoreInfoP, ScoreInfoAverage> collect = scoreInfos.stream()
.collect(Collectors.groupingBy(ScoreInfo::getScoreInfoP, scoreInfoToAverage()));

最新更新