Skip to content
Reliable Data Engineering
Practice problem easy recursionjsonschema
Solve it in the browser (Python editor)

Flatten Nested JSON Records

Difficulty: Easy · Topics: recursion, json, schema · Asked at: Snowflake, Databricks, Stripe

Problem

Write flatten(record) that turns a nested JSON object into a flat dict:

Examples

flatten({"id": 1, "user": {"name": "Ana", "tags": ["a", "b"]}, "meta": {}})
→ {"id": 1, "user.name": "Ana", "user.tags.0": "a", "user.tags.1": "b", "meta": None}

Starter code

def flatten(record: dict, sep: str = ".") -> dict:
    pass

Hints

Hint 1

Recursive helper walk(value, prefix) that handles dict, list, scalar.

Solution

def flatten(record: dict, sep: str = ".") -> dict:
    out = {}

    def walk(value, prefix):
        if isinstance(value, dict):
            if not value and prefix:
                out[prefix] = None
            for k, v in value.items():
                walk(v, f"{prefix}{sep}{k}" if prefix else str(k))
        elif isinstance(value, list):
            if not value:
                out[prefix] = None
            for i, v in enumerate(value):
                walk(v, f"{prefix}{sep}{i}")
        else:
            out[prefix] = value

    walk(record, "")
    return out

Tests

Your solution should pass these:

assert flatten({"id": 1, "user": {"name": "Ana", "tags": ["a", "b"]}, "meta": {}}) == {
    "id": 1, "user.name": "Ana", "user.tags.0": "a", "user.tags.1": "b", "meta": None}
assert flatten({"a": [{"b": 1}, {"b": 2, "c": []}]}) == {"a.0.b": 1, "a.1.b": 2, "a.1.c": None}
assert flatten({}) == {}
assert flatten({"x": None, "y": False}) == {"x": None, "y": False}
assert flatten({"a": {"b": 1}}, sep="__") == {"a__b": 1}

Explanation

O(total number of leaves). Recursion depth equals nesting depth; for adversarial inputs (depth > 1000) use an explicit stack.

Design discussion: indexing list elements into columns (items.0, items.1) is usually the wrong modelling choice for analytics, since column count becomes unbounded. In a lakehouse you’d keep arrays as ARRAY<STRUCT> and explode them into a child table (one row per item). Mention this trade-off.

Follow-up questions

How do you handle key collisions, e.g. {"a.b": 1, "a": {"b": 2}}?

Detect when a key already exists in out and raise or suffix it; or escape the separator in keys. Silent overwrites are data loss.