使用 Java 8 流 API 的累积和

2022-01-22 00:00:00 java-8 java java-stream

我有一个整数列表,比如 list1,我想获得另一个列表 list2,其中包含从开始到当前索引的累积总和.如何使用 Stream API java 8 做到这一点?

I have a List of Integer say list1, and I want to get another list list2 which will contain the cumulative sum up until the current index from start. How can I do this using Stream API java 8 ?

List<Integer> list1 = new ArrayList<>();
list1.addAll(Arrays.asList(1, 2, 3, 4));
List<Integer> list2 = new ArrayList<>();
// initialization
list2.add(list1.get(0));
for(int i=1;i<list1.size();i++) {
// increment step
    list2.add(list2.get(i-1) + list1.get(i));
}

如何将上述命令式代码更改为声明式?

How can I change above imperative style code into declarative one ?

list2 should be [1, 3, 6, 10]

推荐答案

Streams 不适合这种任务,因为涉及到状态(累积部分和).相反,您可以使用 Arrays.parallelPrefix:

Streams are not suited for this kind of task, as there is state involved (the cumulative partial sum). Instead, you could use Arrays.parallelPrefix:

Integer[] arr = list1.toArray(Integer[]::new);

Arrays.parallelPrefix(arr, Integer::sum);

List<Integer> list2 = Arrays.asList(arr);

这首先使用 list1 复制到一个数组中java/util/Collection.html#toArray(java.util.function.IntFunction)" rel="noreferrer">Collection.toArray,从 JDK 11 开始可用.如果你是尚未在 Java 11 上,您可以将第一行替换为传统的 toArray 调用:

This first copies list1 to an array by using Collection.toArray, which is available since JDK 11. If you are not on Java 11 yet, you could replace the first line with the traditional toArray call:

Integer[] arr = list1.toArray(new Integer[0]);

此解决方案不使用流,但它是声明式,因为Arrays.parallelPrefix 接收累积运算作为参数(Integer::sum 在这种情况下).

This solution doesn't use streams, yet it's declarative, because Arrays.parallelPrefix receives the cumulative operation as an argument (Integer::sum in this case).

时间复杂度为 O(N),但可能会涉及一些与设置并行处理所需的基础设施相关的非次要固定成本.但是,根据文档:

Time complexity is O(N), though there might be some non-minor constant costs involved associated with setting up the infrastructure needed for parallel processing. However, according to the docs:

并行前缀计算通常比大型数组的顺序循环更有效

Parallel prefix computation is usually more efficient than sequential loops for large arrays

所以看来这种方法值得一试.

So it seems it's worth giving this approach a try.

另外,值得一提的是,这种方法之所以有效,是因为 Integer::sum 是一个关联运算.这是一个要求.

Also, it's worth mentioning that this approach works because Integer::sum is an associative operation. This is a requirement.

相关文章