~/problems

Problems

Basics first, then the classics, then company-style assessments. Every problem has tests you run right here; multi-level ones unlock as you go. See the roadmap.

Iterators & parsers

Iterators and generators

Resumable/serializable iterators, merging streams, lazy pipelines.

Notes

Recognise it when: you need an iterator over nested or multi-dimensional data, a "resume where you left off", k-way merging of streams, or a lazy pipeline.

class Flatten:
    def __init__(self, nested):
        self.stack = [iter(nested)]

    def __iter__(self):
        return self

    def __next__(self):
        while self.stack:
            try:
                x = next(self.stack[-1])
            except StopIteration:
                self.stack.pop()
                continue
            if isinstance(x, list):
                self.stack.append(iter(x))
            else:
                return x
        raise StopIteration
  • Resumable iterators: make the position explicit state (indexes per dimension, an offset, or a file position) and expose get_state() / set_state(s). Don't pickle a live generator.
  • Merging k sorted streams: a heap of (value, stream_id) pulling lazily with next().
  • Peeking: cache one lookahead element.
  • itertools: chain, islice, groupby (needs sorted input), tee, heapq.merge.

Gotchas: empty inner collections, StopIteration inside generators (PEP 479 turns it into a RuntimeError), and exhausting an iterator twice.

10 problems

Practical systems

Iterators & parsers Lazy sequences, tokenizers and tiny interpreters.

Iterators and generators

esc