如果我有一个java流(例如数字),是否有可能计算(通过将数字加到“以前”计算的和中)?
例如(1,2,3,5,7,9,0) -> (1,3,6,11,18,27,27)
发布于 2022-02-03 10:05:08
java流中的数组之和必须使用。
Integer[] arr = {1, 2, 3, 5, 7, 9, 0};
Arrays.parallelPrefix(arr, (x, y) -> x + y);
System.out.println(Arrays.toString(arr));您必须将用于ArrayList
List<Integer> list = new ArrayList<>();
list.addAll(Arrays.asList(1, 2, 3, 5, 7, 9, 0));
AtomicInteger ai = new AtomicInteger();
List<Integer> sumOfList = list.stream()
.map(ai::addAndGet)
.collect(Collectors.toList());
System.out.println(sumOfList);发布于 2022-02-05 11:47:10
使用流的一个简单解决方案是使用reducing。不过,这个解决方案并不是无状态的。
var inputList = List.of(1, 2, 3, 5, 7, 9, 0);
var result = new ArrayList<>();
var unused = inputList.stream().collect(reducing(0, (a, b) -> {
result.add(a + b);
return a + b;
}));
System.out.println(result); // [1, 3, 6, 11, 18, 27, 27]几点:
在使用流时,应该始终避免
parallelPrefix解决方案应该是首选的解决方案。
发布于 2022-02-03 10:39:43
以下是在this answer上构建概念的证明。它实现了一个具有O(n)时间复杂度的完全无状态解决方案,该解决方案也适用于并行流。
record CumSum(Integer acc, List<Integer> sums) {
public CumSum() {
this(0, List.of());
}
public CumSum collect(Integer n) {
return new CumSum(acc + n, concat(sums, Stream.of(acc + n)));
}
public CumSum combine(CumSum cumSum) {
return new CumSum(acc + cumSum.acc, concat(sums, cumSum.sums.stream().map(n -> acc + n)));
}
private static List<Integer> concat(List<Integer> sums, Stream<Integer> acc) {
return Stream.concat(sums.stream(), acc).toList();
}
}
var list1 = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
var list2 = list1.stream().parallel()
.reduce(new CumSum(), CumSum::collect, CumSum::combine)
.sums;
System.out.println(list2);输出是
[1, 3, 6, 10, 15, 21, 28, 36, 45, 55]不管是否使用并行流。
请注意,由于在Java中缺少真正的不可变列表,CumSum从List和Stream跳来跳去,这不必要地使这个实现复杂化。另外,acc中的单独跟踪可以通过查看sums中的最后一个元素来代替。为了更清楚起见,我选择不这么做。
https://stackoverflow.com/questions/70967347
复制相似问题