本页尚未翻译,因此以英文显示。 参与翻译

Smoothed zone changes

FxDart wins

Requirement

A temperature sensor reports twelve raw readings per day. Smooth them with a 3-reading moving average, classify each smoothed value into a zone (cool < 20° ≤ ok < 25° ≤ hot), and report every zone transition — which zone it left, which it entered, and the smoothed values on both sides. A day with no transitions prints a single stable line instead of nothing. The data for two July days is in the code; both versions must print the lines shown under Expected output.

Expected output
2026-07-14 (3-reading moving average):
  cool → ok (avg 18.6 → 21.2)
  ok → hot (avg 21.2 → 25.6)
  hot → ok (avg 25.6 → 24.9)
2026-07-15 (3-reading moving average):
  stable — no zone changes

Side by side

Native Dart

FxDart

Why they differ

Every stage of this task needs to see neighboring elements, and that is exactly where native Dart runs out of vocabulary: no sliding window, no adjacent-dedup, no successor pairing — in the standard library or in package:collection (slices tiles without overlap). So the native version is three index loops, each carrying its own mutable state: a windowed sum, a runStarts list compared against its own tail, and an i - 1 lookback for the transition lines, plus a final isEmpty patch-up for the stable day.

The FxDart chain states the five stages in the order the data flows: windowed(3)average per window, uniqAdjacentBy(zone) keeps the first smoothed value of each zone run, pairwise turns run-starts into (from, to) transitions, and ifEmpty supplies the stable-day line inside the pipeline instead of an if-check after it. Each fragment is independently testable, and none of it re-implements window bounds. These four operators are pull-model ports of the Rx windowing family.

Benchmark

Apple M1 Max, 32 GB RAM · Dart 3.12.2 (AOT-compiled) · 2026-08-24

N = 100

Time Tie

Native Dart 2.3 µs
FxDart 4.3 µs

Peak memory Tie

Native Dart 16.4 MB
FxDart 16.3 MB

N = 10,000

Time Tie

Native Dart 194 µs
FxDart 410 µs

Peak memory Tie

Native Dart 22.5 MB
FxDart 22.7 MB

N = 1,000,000

Time FxDart wins

Native Dart 39.4 ms
FxDart 37.4 ms

Peak memory FxDart wins

Native Dart 237.3 MB
FxDart 81.8 MB

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.