我一直在尝试使用Java 8流,这是删除最低和最高分数的最佳方法。
private final Set<MatchScore> scores = new HashSet<>(10);
. . .
public double OPR() {
return scores.stream()
.mapToDouble(MatchScore::getScore)
.filter((num) -> { //Exclude min and max score
return num != scores.stream()
.mapToDouble(MatchScore::getScore)
.max().getAsDouble()
&&
num != scores.stream()
.mapToDouble(MatchScore::getScore)
.min().getAsDouble();
})
.average().getAsDouble();
}
答案 0 :(得分:8)
更简单的方法是:
return scores.stream()
.mapToDouble(MatchScore::getScore)
.sorted()
.skip(1)
.limit(scores.size() - 2)
.average().getAsDouble();
注意:这是有效的,因为集合中的元素是唯一的 - 列表中可能有多个元素等于最小或最大分数。
性能方面*,跳过/限制在一小组10个元素上显着更快(均值列显示样本调用所用的平均时间,以纳秒为单位):
Benchmark Mode Samples Mean Mean error Units
c.a.p.SO22923505.maxMin avgt 5 6996.190 284.287 ns/op
c.a.p.SO22923505.skipLimit avgt 5 479.935 4.547 ns/op
*使用jmh - 这里是the source code for the tests。 子>
答案 1 :(得分:4)
可以使用DoubleSummaryStatistics
在数据的一次传递中收集所需信息,然后减去最小值和最大值:
@GenerateMicroBenchmark
public double summaryStats() {
DoubleSummaryStatistics stats =
scores.stream()
.collect(Collectors.summarizingDouble(Double::doubleValue));
if (stats.getCount() == 0L) {
return 0.0; // or something
} else {
return (stats.getSum() - stats.getMin() - stats.getMax()) / (stats.getCount() - 2);
}
}
将此代码添加到assylias&#39;基准代码给了我以下结果。虽然我的机器整体速度较慢,但在单次通过中使用DoubleSummaryStatistics
的相对性能更快。
Benchmark Mode Samples Mean Mean error Units
c.a.p.SO22923505.maxMin avgt 5 9629.166 1051.585 ns/op
c.a.p.SO22923505.skipLimit avgt 5 682.221 80.504 ns/op
c.a.p.SO22923505.summaryStats avgt 5 412.740 85.372 ns/op
答案 2 :(得分:2)
我认为这样做无需在流中进行多次传递或对其进行排序:
private static class ScoreData {
public double min, max, sum;
public int count;
public ScoreData() {
min = Double.POSITIVE_INFINITY;
max = Double.NEGATIVE_INFINITY;
sum = 0;
count = 0;
}
public void add(double d) {
if (d < min)
min = d;
if (d > max)
max = d;
sum += d;
count++;
}
public void combine(ScoreData m) {
if (m.min < min)
min = m.min;
if (m.max > max)
max = m.max;
sum += m.sum;
count += m.count;
}
}
private static ScoreData getScoreData(DoubleStream ds) {
return ds.collect(ScoreData::new, ScoreData::add, ScoreData::combine);
}
适用于任何DoubleStream
。现在你可以得到不包括像
ScoreData sd = getScoreData(scores.stream().mapToDouble(MatchScore::getScore));
double answer = (sd.sum - sd.min - sd.max) / (sd.count - 2);
假设sd.count > 2
。
编辑:看起来我刚刚重新发明轮子! Stuart有一个更好的解决方案,使用JDK中已经存在的类。