Where the Line Breaks
An easy Python interview practice problem on DataDriven. Write the Python and run it against test cases, with instant feedback.
- Domain
- Python
- Difficulty
- easy
- Seniority
- L3
- Asked in
- Braze
Problem
Given a list of log records in arrival order and a batch size n, return the batches a downstream consumer will take, since it accepts at most n entries at a time. Tag each batch with its position in the sequence and whether it is the final one.
Every batch has a last piece. Mark it right.
Example 1
Input:
records = [1,2,3,4,5], n = 2
Output:
[{"batch_index":0,"records":[1,2],"is_last":false},{"batch_index":1,"records":[3,4],"is_last":false},{"batch_index":2,"records":[5],"is_last":true}]Example 2
Input:
records = [10,20,30], n = 3
Output:
[{"batch_index":0,"records":[10,20,30],"is_last":true}]Worked solution and explanation
What this problem is really testing
On its face this is textbook chunking: slice the list every n elements. The real work is the is_last flag, and this is where careful candidates get burned. The tempting move is to mark a chunk last when it comes up short (len(batch) < n). That reads fine until the record count divides evenly by n: now every chunk is full, the size test never fires, and NOTHING gets flagged as last. The flag has to come from position (i + n >= total), not from size. Get it wrong and a downstream consumer waiting on is_last to flush never fires on a clean multiple, and the final batch quietly disappears.
Break down the requirements
Step 1: Chunk the list into batches of size n
Use range with step n and list slicing, the standard chunking pattern. Slicing past the end is safe in Python, so the final short chunk needs no special case.
Step 2: Wrap each batch with its index and is_last flag
Track the batch index as you iterate, and compute is_last from position: the last batch is the one where i + n reaches or exceeds the total length. Do NOT infer it from the chunk's length.
Step 3: Handle empty input
An empty records list should return an empty list of batches, not a single empty batch. The range-with-step loop gives this for free: it never enters the loop body.
The solution
def batch_with_metadata(records, n):
result = []
total = len(records)
batch_index = 0
for i in range(0, total, n):
batch = records[i:i + n]
is_last = (i + n) >= total
result.append({
'batch_index': batch_index,
'records': batch,
'is_last': is_last,
})
batch_index += 1
return result- Size-based flag (wrong)
is_last= len(batch) < n. On records=[1,2,3,4], n=2 both chunks are full, sois_lastis False everywhere. No chunk is ever marked last.- Position-based flag (correct)
is_last= (i + n) >= total. On the same input the second chunk starts at i=2, and 2 + 2 >= 4, so it is correctly flagged last.
Common follow-up questions
- What if the caller also needs a `total_batches` count in each wrapper? (Tests whether you can pre-compute the count using ceiling division before iterating.)
- How would you stream batches to an API with retry logic? (Tests knowledge of generator-based batching with error handling per batch.)
- What if records arrive as a stream rather than a list? (Tests iterator-based approaches where you cannot call len() upfront, so `is_last` can only be known by lookahead.)