~/problems / Iterators & parsers / Iterators and generators

Range Iterator

easy ~15 min Coinbase

Build RangeIterator(start, end, step=1), an iterator over integers that behaves like Python's range but is written by hand (don't call range or itertools inside it).

  • It produces start, start + step, start + 2*step, … and stops before reaching end (end is exclusive).
  • A positive step counts upwards and stops once a value would be >= end; a negative step counts downwards and stops once a value would be <= end.
  • If the direction of step can never reach end (for example start=5, end=1, step=2), the iterator is simply empty.
  • step == 0 raises ValueError in the constructor.

Methods:

  • has_next() -> bool: is there another value?
  • next() -> int: return the next value and advance. Raise StopIteration when exhausted.
  • remaining() -> int: how many values are still to come, in O(1).
  • It must also work in a for loop: implement __iter__ (returning self) and __next__.
it = RangeIterator(2, 11, 3)
it.remaining()     # 3
it.next()          # 2
list(it)           # [5, 8]
it.has_next()      # False

list(RangeIterator(10, 0, -4))   # [10, 6, 2]
list(RangeIterator(-3, -3))      # []
list(RangeIterator(5, 1, 2))     # []

Values can be as large as 10**18, and a range may hold that many values: the iterator must be lazy (constant memory, O(1) per call).

Show hint

Keep only the next value to produce. With step > 0 the next value exists while cur < end; with step < 0, while cur > end. The count left is a ceiling division: max(0, (end - cur + step - (1 if step > 0 else -1)) // step).

Topic: Iterators and generators. Resumable/serializable iterators, merging streams, lazy pipelines.

0:00
Ctrl ' run · Ctrl ↵ submit
esc