uniqAdjacent
Drops elements equal to their predecessor — only adjacent duplicates go, and no seen-set builds up.
Lecture
uniq answers "have I ever
seen this value?" — it keeps a set of everything seen so far.
uniqAdjacent() answers a different question:
"did the value change?" It compares each element only with
its immediate predecessor, so [1, 1, 2, 2, 1] becomes
(1, 2, 1) — the trailing 1 survives, because
it is a new run, not a repeat of the current one.
That makes it the operator for collapsing runs: status feeds that
re-report the same state every tick, sensor values that plateau, log
streams that repeat a level. And because there is no seen-set, memory
stays constant no matter how long the sequence — safe on endless
sources where uniq would grow forever.
uniqAdjacentBy(key) compares by a derived key, mirroring
uniqBy.
fxdart extension (no FxTS counterpart) — Rx calls it
distinctUntilChanged, Dart streams call it
Stream.distinct. The async key callback runs one element
at a time (the comparison is inherently ordered), but the upstream
still evaluates in parallel under
concurrent.
Demo 1 · Collapse runs, keep returns
Demo 2 · State changes by key
Try it yourself
Exercise: report only the moments a sensor's zone changes.