The Chunked Reader
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
- L3
- Asked in
- Athenahealth
Problem
A batch shipper can only send chunk_size log lines per request, so a run of lines has to be split into successive batches before it goes out. Split lines into batches of at most chunk_size in their original order, and return the batches as a list of lists.
Too big for one payload. Ship it in pieces.
Example
Input:
lines = ["a","b","c","d","e"], chunk_size = 2
Output:
[["a","b"],["c","d"],["e"]]
Worked solution and explanation
How this problem really reads
Strip the costume and this is fixed-size batching with a ragged tail. Everyone can chop a list into pieces; what separates candidates is the last partial batch and not confusing indices with slices. The trap: reach for range(0, len(lines), chunk_size) and you hand back a list of integers instead of a list of lines, or special-case the tail by hand and you drop or duplicate the final element. The move is to stride the read position by chunk_size and let slicing clamp the last batch for you, producing one batch at a time so the batching logic stays reusable for a streaming caller even though this entrypoint materializes the result.
Break down the requirements
Step 1: Use a position pointer starting at 0
Track your current read position in the list. This replaces any need to mutate the input.
Step 2: Yield slices of chunk_size
On each iteration, yield lines[pos:pos + chunk_size]. Python slicing handles the case where fewer than chunk_size elements remain, so the ragged tail comes out for free.
Step 3: Advance the pointer
Increment pos by chunk_size after each yield. The loop ends when pos reaches or passes the list length, which is also how an empty input yields nothing.
Step 4: Materialize the batches into the returned list
Drive the generator from the entrypoint and collect its batches with list(...), returning a list of lists. The generator stays lazy; only the final return materializes.
The solution
def chunked_read(lines: list, chunk_size: int):
def _batches():
pos = 0
while pos < len(lines):
yield lines[pos:pos + chunk_size]
pos += chunk_size
return list(_batches())Common follow-up questions
- What if the input were a file handle instead of a list? (Tests whether you can adapt from list slicing to `readline()` or `read(n)` in a truly streaming context where the input never fits in memory.)
- How would you process the batches in parallel? (Tests knowledge of concurrent.futures or multiprocessing patterns fed by a generator.)
- What happens when `chunk_size` is larger than the input? (Tests edge-case awareness: the generator yields a single batch holding every element.)