Three-reading moving average
Requirement
Smooth eight hourly temperature readings with a three-reading moving average: for every window of 3 consecutive readings, print the window and its mean to one decimal place — six full windows, no partials. The data is in the code; both versions must print the lines shown under Expected output.
Expected output
21.0 21.6 22.4 -> avg 21.7 21.6 22.4 23.1 -> avg 22.4 22.4 23.1 22.8 -> avg 22.8 23.1 22.8 22.2 -> avg 22.7 22.8 22.2 21.9 -> avg 22.3 22.2 21.9 21.4 -> avg 21.8
Side by side
RxDart
FxDart
Why they differ
RxDart spells a sliding window as a parameterisation of batching:
bufferCount(3, 1) — buffers of three, a new buffer
starting every one event. It works, but the encoding leaks twice.
You have to know that the second argument is
startBufferEvery and that 1 means
"sliding"; and at the end of the stream the operator flushes its
still-open buffers, so a ramp-down partial like
[21.9, 21.4] comes out too and a
where((w) => w.length == 3) has to stand guard for a
case the requirement never mentioned.
FxDart has a word for the concept itself: windowed(3)
yields exactly the full windows, and partial: true is
the explicit opt-in for the ramp-down — the default matches what a
moving average means. Add average as a library function
(RxDart has no aggregate helpers, so the mean is a hand-rolled
reduce-and-divide) and the pull side states the
requirement while the push side encodes it. That gap is vocabulary,
not model — but the vocabulary exists because windows over an
iterable are a pull-native idea, and this one goes to FxDart.
Benchmark
N = 100
Time Tie
Peak memory Tie
N = 1,000,000
Time FxDart wins
Peak memory Tie
Bars are medians of repeated timed iterations in fresh processes per side (small N is batched for timer resolution). Sides within 5% of each other — or within 0.6 ms, a difference no person can perceive — count as a tie; close relative races are re-measured up to 5 runs. In an app, anything under a few milliseconds is invisible to the user regardless of which bar is shorter. Memory is peak process RSS. The Dart VM and the dataset are identical on both sides, so the difference between the two bars is what the pipeline itself holds onto.