Reduce & checkpoint
Fold the whole stream into one value, or a few items
.reduce(acc, reducer) folds the stream with reducer(item, acc) and emits a single item, the final accumulator, when the stream ends. .wait_and_reduce(acc, reducer) does the same and returns the value directly (blocking). Mind the argument order: item first, accumulator second.
Signature
Pipeline.reduce(accumulator, reducer) -> Pipeline[OutPacket]
Pipeline.wait_and_reduce(accumulator, reducer) -> OutPacket
Pipeline.checkpoint(initial, reducer, emitter) -> Pipeline[OutPacket]
# reducer(item, accumulator) -> accumulatorfrom olympipe import Pipeline
def add(item: int, total: int) -> int: # reducer(item, accumulator)
return total + item
# Blocking: returns the final accumulator directly
print(Pipeline(range(101)).wait_and_reduce(0, add))
# As a step: emits a single item when the stream ends
print(Pipeline(range(101)).reduce(0, add).task(lambda t: t * 2).wait_for_result())5050
[10100]How it works
The reduction runs in a single process that keeps the accumulator in memory. If an error occurs during the reduction, the partial accumulator is not emitted: the pipeline fails with PipelineExecutionError.
checkpoint: accumulate a state, then emit several items
.checkpoint(initial, reducer, emitter) updates a state with reducer(item, state) (which must return the state), then, once the stream ends, calls emitter(state) and emits each element of the returned iterable. Handy for a top-N, a histogram or deduplication.
from collections import Counter
from olympipe import Pipeline
def count_word(word: str, counts: Counter) -> Counter:
counts[word] += 1
return counts # the reducer must return the state
def top_words(counts: Counter) -> list[tuple[str, int]]:
return counts.most_common(2) # emitted items, one by one
words = "a b a c b a d".split()
print(
Pipeline(words)
.checkpoint(Counter(), count_word, top_words)
.wait_for_result()
)[('a', 3), ('b', 2)]