使用java 8我想从列表中创建一个新集合,并在此过程中累积一笔金额。
源列表由看起来像这样的对象组成:
class Event {
String description;
double sum;
}
使用这样的示例列表:
{ { "desc1", 10.0 }, {"desc2", 14.0 }, {"desc3", 5.0 } }
结果列表应如下所示
我知道如何总结得到最终总和,在本例中为29.0,但我想创建结果列表,同时累积总和。
如何使用Java8执行此操作?
答案 0 :(得分:4)
您可以通过实现自己的收集器来执行此操作,以执行映射和求和。您的流媒体代码如下所示:
List<SummedEvent> summedEvents = events.stream().collect(EventConsumer::new, EventConsumer::accept, EventConsumer::combine).summedEvents();
summedEvents.forEach((se) -> System.out.println(String.format("%s, %2f, %2f", se.description, se.sum, se.runningTotal)));
为此,我假设了一个新的课程SummedEvent
,它也保留了总课程。然后,您的收集器类将实现如下:
class EventConsumer {
private List<SummedEvent> summedEvents = new ArrayList<>();
private double runningTotal = 0;
public void accept(Event event) {
runningTotal += event.sum;
summedEvents.add(new SummedEvent(event.description, event.sum, runningTotal));
}
public void combine(EventConsumer other) {
this.summedEvents.addAll(other.summedEvents);
this.runningTotal += other.runningTotal;
}
public List<SummedEvent> summedEvents() {
return summedEvents;
}
}
答案 1 :(得分:3)
如果您将按顺序运行管道,则可以使用peek
double[] acc = {0};
List<CustomEvent> list = originalList.stream()
.peek(e -> acc[0] += e.sum)
.map(e -> new CustomEvent(e, acc[0]))
.collect(toList());
请注意,如果你得到错误的结果 流并行运行。
但是我不确定管道是否可以在一次传递中并行运行,但假设基础列表可以快速访问索引i
处的元素,您可以这样做:
double[] acc = originalList.stream().mapToDouble(e -> e.sum).toArray();
Arrays.parallelPrefix(acc, Double::sum);
List<CustomEvent> lx = IntStream.range(0, originalList.size())
.parallel()
.mapToObj(i -> new CustomEvent(originalList.get(i), acc[i]))
.collect(toList());
parallelPrefix
将应用您正在寻找总和的减少量。然后你只需要流式传输索引,然后将每个事件映射到相应的累计总和。