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

Point-of-sale transaction events arrive nested: each event has a store_id, a timestamp, and an items list of line items with an item_name and item_price. Flatten events into one record per line item that carries its parent's store_id and timestamp, keeping the order the events and their items arrived in.

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 = [{"items":[],"store_id":"S003","timestamp":"2024-01-16T09:00:00"},{"items":[{"item_name":"soda","item_price":1.5}],"store_id":"S004","timestamp":"2024-01-16T09:05:00"}]

Output:

[{"store_id":"S004","item_name":"soda","timestamp":"2024-01-16T09:05:00","item_price":1.5}]

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