A greenhouse humidity sensor reports a value every second, and most of the time the value doesn't change. Before sending the stream over a slow radio link, you collapse each run of equal consecutive readings into one (value, count) pair. The stream never ends, so this must work lazily, one pair at a time.
Implement class Runs:
Runs(iterable)wraps any iterable, including generators and infinite ones.- Iterating yields
(value, count)tuples: each maximal run of consecutive equal items (compared with==) becomes one tuple, in order. Equal values that are not next to each other form separate runs. iter(runs)returns the object itself; once exhausted, every furthernext()keeps raisingStopIteration.- Lazy: to finish a run you must read one item past it (that's how you know it ended). Keep that item for the next run instead of losing it, and never read further ahead than that.
list(Runs([55, 55, 55, 56, 55, 55])) # [(55, 3), (56, 1), (55, 2)]
list(Runs("aab")) # [("a", 2), ("b", 1)]
list(Runs([])) # []
import itertools
r = Runs(itertools.cycle([1, 1, 2])) # 1 1 2 1 1 2 ...
next(r) # (1, 2)
next(r) # (2, 1)
next(r) # (1, 2)
Write it as a class with __iter__ and __next__ (not a generator function, and not itertools.groupby).
Show hint
Store iter(iterable) and a "pending" item (with a sentinel _EMPTY = object() meaning "nothing held"). In __next__: take the pending item (or pull one; if the source is dry, raise StopIteration), then keep pulling while items equal it, counting them; the first different item becomes the new pending one.