~/problems / Iterators & parsers / Iterators and generators

OA: Resumable iterators (list, 2D, 3D, file)

medium 4 levels ~80 min OpenAI

Level 1 Base class and list iterator

You are building iterators that can be paused and resumed: a job iterates for a while, saves its position as plain data, and later (maybe in a different process) a fresh iterator over the same data picks up exactly where it stopped.

Part A — the contract. Write an abstract base class ResumableIterator (use abc.ABC) with:

  • __iter__() returning self (implemented in the base class),
  • abstract __next__(), get_state() -> dict and set_state(state: dict) -> None.

The base class itself, and any subclass that leaves one of the abstract methods out, must be impossible to instantiate (TypeError).

Part B — ResumableListIterator(items), a subclass that walks a Python list.

Rules for states (they apply to every iterator in this problem):

  • get_state() returns a new dict built only from JSON types (dict, list, str, int, float, bool, None). It must survive json.loads(json.dumps(state)). Later calls to next must not change a dict you already returned.
  • A state is small: it stores positions and counts, never the items. Its JSON must stay under 200 characters no matter how big the data is.
  • get_state() never moves the iterator; calling it many times in a row is fine.
  • set_state(state) on any iterator of the same class over the same data restores the position, including the "finished" position.
  • set_state raises ValueError (not KeyError / TypeError) and leaves the position unchanged when the state is unusable: malformed or missing fields, an index out of range, a state produced by a different iterator class, or a state saved over a list of a different length. The tests validate every field your state contains: they remove each field in turn, and set each integer field to values such as -1, an out-of-range 10**6, "3" or None, and expect ValueError every time. So don't add fields you don't check. Tip: store a "kind" tag and the data length in every state.
it = ResumableListIterator(["a", "b", "c", "d"])
next(it), next(it)          # "a", "b"
saved = it.get_state()
next(it)                    # "c"
it.set_state(saved)
list(it)                    # ["c", "d"]

fresh = ResumableListIterator(["a", "b", "c", "d"])
fresh.set_state(saved)
next(fresh)                 # "c"
ResumableListIterator([1, 2]).set_state(saved)   # ValueError: different length

An empty list stops immediately. next after the end keeps raising StopIteration.

Level 2 unlocks when level 1 passes.

Level 3 unlocks when level 2 passes.

Level 4 unlocks when level 3 passes.

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

0:00
Ctrl ' run · Ctrl ↵ submit
esc