Problem 80 · Object & System Design
Peeking Iterator
01Problem
Wrap any iterator to support peek() (return next element without advancing), next(), and has_next(). Must work for iterators that may yield None.
02Key insight
Cache exactly one lookahead element plus a separate 'has cached' flag (not a None check, since None is a valid element). This is the building block for k-way merges and merge joins.
03Solution
Try it first.
TimeO(1) per op
SpaceO(1)
tests.py · 4 passing
tests.pypython6 lines
p = PeekingIterator([1, 2, 3])
assert p.next() == 1 and p.peek() == 2 and p.peek() == 2 and p.next() == 2
assert p.next() == 3 and not p.has_next()
q = PeekingIterator([None, 0])
assert q.has_next() and q.peek() is None and q.next() is None and q.next() == 0
assert list(PeekingIterator(x for x in "ab")) == ["a", "b"]04Staff-level follow-up
Use it for an external k-way merge of sorted runs: a heap of (peek(), run_id) across PeekingIterators streams the merge with O(k) memory, the core of LSM compaction and sort-merge joins.