我怀疑你的任务非常适合流.您正在寻找的是典型的扫描左操作,其本质上是顺序操作.
例如,想象一下管道中的以下元素:[1,2,-4,5].并行执行可以将其分成两个子部分,即[1,2]和[-4,5].那你会用它们做什么?你不能独立地对它们求和,因为它会产生[3]和[1],然后你就失去了1 2 – 4 <1的事实. 0被尊重. 因此,即使你编写了一个跟踪索引和总和的收集器,它也无法并行执行(我怀疑你甚至可以从中受益)但你可以想象这样的收集器可以顺序使用:
public static Collector indexSumLeft(int limit) {
return Collector.of(
() -> new int[]{-1, 0, 0},
(arr, elem) -> {
if(arr[2] == 0) {
arr[1] += elem;
arr[0]++;
}
if(arr[1] < limit) {
arr[2] = 1;
}
},
(arr1, arr2) -> {throw new UnsupportedOperationException("Cannot run in parallel");},
arr -> arr[0]
);
}
一个简单的用法:
int index = IntStream.of(arr).boxed().collect(indexSumLeft(0));
这仍将遍历管道的所有元素,因此效率不高.
如果数据源是数组,您也可以考虑使用Arrays.parallelPrefix.只需计算其上的部分和,然后使用流来查找总和低于限制的第一个索引.
Arrays.parallelPrefix(arr, Integer::sum);
int index = IntStream.range(0, arr.length)
.filter(i -> arr[i] < limit)
.findFirst()
.orElse(-1);
这里也计算了所有的部分和(但是并行).
简而言之,我会使用一个简单的for循环.