2

Java 8 を使用して、リストから新しいコレクションを作成し、途中で合計を累積したいと考えています。

ソース リストは、次のようなオブジェクトで構成されます。

class Event {
  String description;
  double sum;
}

次のようなリストの例を使用します。

{ { "desc1", 10.0 }, {"desc2", 14.0 }, {"desc3", 5.0 } }

結果のリストは次のようになります

  • desc1、10.0、10.0
  • desc2、14.0、24.0
  • desc3、5.0、29.0

最終的な合計 (この場合は 29.0) を得るために合計する方法は知っていますが、結果リストを作成し、同時に合計を途中で累積したいと考えています。

Java8でこれを行うにはどうすればよいですか?

4

2 に答える 2

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;
    }
}
于 2015-03-14T12:47:50.913 に答える
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());

ストリームを並行して実行すると、間違った結果が得られることに注意してください。

ただし、パイプラインを 1 つのパスで並列に実行できるかどうかはわかりませんが、基になるリストが index の要素に高速にアクセスできると仮定すると、次の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合計を探している削減が適用されます。次に、インデックスをストリーミングし、各イベントを対応する累積合計にマップするだけです。

于 2015-03-14T13:25:52.127 に答える