The Page Turner

A medium Python interview practice problem on DataDriven. Write the Python and run it against test cases, with instant feedback.

Domain
Python
Difficulty
medium
Seniority
L4
Asked in
Foursquare

Problem

A paged API returns pages, a list of pages where each page is a list of items and any page can come back empty. Inside paginate(pages), build a class that implements __iter__ and __next__ and hands out the items one at a time, keeping its place between calls, then return everything it yields as a list.

Nobody loads everything at once.

Example 1

Input:

pages = [[1,2],[3,4]]

Output:

[1,2,3,4]

Example 2

Input:

pages = []

Output:

[]

Worked solution and explanation

Why this problem exists in real interviews

Pagination shows up in every API and every analytics pipeline. Interviewers use this prompt to check whether you understand the Python iterator protocol (__iter__ and __next__), and whether you can flatten a nested structure lazily without materializing the whole feed in memory.


Break down the requirements

Step 1: Make the class its own iterator

__iter__ returns self so for item in Paginator(pages) and list(Paginator(pages)) both work. The driver paginate(pages) calls list(Paginator(pages)), which calls __iter__ then __next__ until StopIteration.

Step 2: Track two indices, not one flat cursor

Keep page_idx for which page you are on and item_idx for the position inside that page. A single flat cursor would force you to either pre-flatten the input or recompute offsets on every call.

Step 3: Skip empty pages and stop cleanly

Use a while loop in __next__ so that an empty page advances page_idx without returning anything. When page_idx runs past the end, raise StopIteration (do not return None). Expose a tiny top-level driver paginate(pages) that returns list(Paginator(pages)) so the harness has a single callable to invoke.


The solution

Custom iterator with two-level index tracking
def paginate(pages: list[list]) -> list:
    class Paginator:
        def __init__(self, pages: list[list]):
            self.pages = pages
            self.page_idx = 0
            self.item_idx = 0

        def __iter__(self):
            return self

        def __next__(self):
            while self.page_idx < len(self.pages):
                page = self.pages[self.page_idx]
                if self.item_idx < len(page):
                    item = page[self.item_idx]
                    self.item_idx += 1
                    return item
                self.page_idx += 1
                self.item_idx = 0
            raise StopIteration

    return list(Paginator(pages))

Common follow-up questions