public static double[] movingAverage(double[] values,int n) {
double [] sums = Arrays.copyOf(values, values.length); // 1
Arrays.parallelPrefix(sums, Double::sum); // 2
int start = n - 1;
return IntStream.range(start, sums.length)
.mapToDouble(i -> {
double prefix = i == start ? 0 : sums[i - n];
return (sums[i] - prefix) / n; //4
}).toArray();
}
摘自:《java 8 函数式编程》
解释:
这段代码有点复杂,我会分步介绍它是如何工作的。参数n是时间窗口的大小,我们据此计算滑动平均值。由于要使用的并行操作会改变数组内容,为了不修改原有数据,在➊处复制了一份输入数据。
在➋处执行并行操作,将数组的元素相加。现在sums变量中保存了求和结果。比如输入0、1、2、3、4、3.5,则计算后的值为0.0、1.0、3.0、6.0、10.0、13.5。现在有了和,就能计算出时间窗口中的和了,减去窗口起始位置的元素即可,除以n即得到平均值。可以使用已有的流中的方法计算该值,那就让我们来试试吧!使用Intstream.range得到包含所需元素下标的流。
在➍处使用总和减去窗口起始值,然后再除以n得到平均值。
最后在➎处将流转换为数组。
算法举例:
计算 double [] values = [1.0, 2.0, 3.0, 4.0, 3.5] n为3的窗口滑动
第一次获取值为 1.0, 2.0, 3.0 ,sums 下标为2即可取到和 6.0 ,求得平平均值为 2.0
第二次获取值为 2.0, 3.0, 4.0 ,sums 下标为3即可取到和 10.0,求得平平均值为 10.0 / 3
第三次获取值为 3.0, 4.0, 3.5 ,sums 下标为4即可取到和 13.5,求得平平均值为 13.5 / 3
最终 求得值为 (2.0 + 10.0 / 3 + 13.5 / 3) / 3