Every Line on the Receipt

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
L5
Asked in
Walmart

Problem

Transaction events arrive as nested structures: each event is a dict with a store_id (str), a timestamp (str), and an items list of dicts (each item has item_name and item_price). Write flatten_transactions(events) that explodes every event into one record per item, returning a flat list of dicts where each record carries store_id, item_name, timestamp, and item_price from its parent transaction. An event with an empty items list produces zero records, and an empty input list returns an empty list. Keep events in input order and items in their listed order within each event.

Nested deep inside the receipt. Pull every item out.

Example 1

Input:

events = [{"items":[{"item_name":"milk","item_price":3.99},{"item_name":"bread","item_price":2.49}],"store_id":"S001","timestamp":"2024-01-15T10:30:00"},{"items":[{"item_name":"eggs","item_price":4.29}],"store_id":"S002","timestamp":"2024-01-15T11:00:00"}]

Output:

[{"store_id":"S001","item_name":"milk","timestamp":"2024-01-15T10:30:00","item_price":3.99},{"store_id":"S001","item_name":"bread","timestamp":"2024-01-15T10:30:00","item_price":2.49},{"store_id":"S002","item_name":"eggs","timestamp":"2024-01-15T11:00:00","item_price":4.29}]

Example 2

Input:

events = []

Output:

[]

Worked solution and explanation

Why this problem exists in real interviews

This is a parent-child explode wearing a receipt costume. Retail point-of-sale data almost never arrives in the shape analytics needs: a transaction is one header (store, timestamp) wrapping a list of line items, and the row count you owe the warehouse is the total number of items, not the number of transactions. The real skill being probed is whether you can carry the header fields DOWN onto every child while nested-iterating, and whether you trust an empty inner list to disappear on its own. Anyone can write the two loops. The tell is what you do with a voided transaction: reach for an if not items branch and you corrupt the fact table.


Break down the requirements

Step 1: Walk the events in input order

The outer structure is a list of transaction dicts. Iterate it as given so the emitted rows stay deterministic; nothing here should sort or regroup.

Step 2: Explode each event's items

For each event, iterate its items list in its listed order. Each item becomes exactly one output record, so the inner loop is where rows are actually born.

Step 3: Carry the header onto every line

Read store_id and timestamp once per event, then stamp them onto each item's record alongside item_name and item_price. Every output dict has exactly these four keys.

Step 4: Let empty lists drop out by construction

An event with an empty items list runs the inner loop zero times and contributes nothing; an empty events list yields an empty result. No special-case branch, and never a placeholder or None-filled row.


The solution

flatten_transactions
def flatten_transactions(events):
    rows = []
    for event in events:
        store_id = event['store_id']
        timestamp = event['timestamp']
        for item in event['items']:
            rows.append({
                'store_id': store_id,
                'item_name': item['item_name'],
                'timestamp': timestamp,
                'item_price': item['item_price'],
            })
    return rows

Outer loop pins the header, inner loop emits one row per item.


Follow-up questions an interviewer may ask

Common follow-up questions