# All the Way Down

> However deep it nests, every leaf belongs on one line.

Canonical URL: <https://datadriven.io/problems/all_the_way_down>

Domain: Python · Difficulty: medium · Seniority: L4

## Problem

A config export arrives as a list whose entries are either plain values or further lists, nested to arbitrary depth with no fixed structure. Collapse it into a single flat list holding every leaf value in left-to-right order. Treat strings as leaf values, not as sequences to descend into.

## Worked solution and explanation

### What this really is

Strip the costume off and this is a tree traversal wearing a list. Every value with brackets around it is an internal node; the numbers and strings you actually want are the leaves. Once you see it that way, the whole problem collapses to one decision made at every element: is this a branch I descend into, or a leaf I keep? The trap is the definition of 'leaf'. A string is iterable, so the lazy 'can I loop over it?' test walks straight into 'abc' and hands you back 'a', 'b', 'c'. That is the single mistake that separates a clean answer from a buggy one.

> **The one decision**
>
> There is exactly one test that matters: isinstance(item, list). If it is a list, recurse and splice the results in. If it is anything else, including a string, it is a leaf and goes straight into the output. Get that one predicate right and the rest writes itself.

> **The string trap**
>
> Reaching for a generic 'is it iterable?' check (or hasattr __iter__). Strings pass it, so 'bc' stops being a value and becomes two characters. Test for list specifically. The prompt makes strings leaves precisely to catch this.

---

### Building it

#### Step 1: One ordered pass

Walk the list once, in order, and ask the leaf-vs-branch question per element. Left-to-right iteration is what preserves output order for free; you never sort or reverse anything.

#### Step 2: Recurse and splice

When the element is a list, call yourself on it. The recursive call returns an already-flat list, so extend the accumulator with it. Using extend (not a nested append loop) keeps the splice in one readable line at the same cost.

#### Step 3: Collect leaves whole

Otherwise the element is a leaf: append it as-is. Numbers, strings, anything non-list lands here untouched.

---

### The solution

**Recursive flatten**

```python
def deep_flatten(nested):
    result = []
    for item in nested:
        if isinstance(item, list):
            result.extend(deep_flatten(item))
        else:
            result.append(item)
    return result
```

*One list check per element; recursion handles arbitrary depth.*

> **Cost**
>
> Time is O(n) in the total number of elements across every level: each leaf is appended once and each sublist is descended once. Space is O(n + d), where n is the output and d is the deepest nesting level held on the recursion stack.

**Naive iterable check**

if hasattr(item, '__iter__'): recurse. Looks general, but strings are iterable, so 'bc' silently explodes into 'b', 'c' and the output is wrong in a way the simple test cases may not catch.

**List check**

if isinstance(item, list): recurse. Descends only into the one container the problem cares about. Strings, tuples, and dicts are all kept as single leaf values, which is exactly the contract.

> **Interviewers watch for**
>
> isinstance(item, list) over type(item) == list (it respects list subclasses and reads as idiomatic Python), and whether you can articulate that strings are the edge case. Naming the recursion-limit risk for pathological depth, even if you do not implement the iterative version, signals systems awareness.

> **In production**
>
> This shape shows up constantly in config and document handling: nested JSON, tree-structured settings, deeply nested API payloads. The leaf-vs-container decision is the same one you make when normalizing those into flat rows for a warehouse.

## Common follow-up questions

- What if the nesting depth could exceed Python's recursion limit? _(Tests iterative flattening with an explicit stack.)_
- How would you handle dicts nested inside the lists? _(Tests refining the container check so dicts are flattened by value rather than descended like lists.)_
- What if tuples and sets also counted as containers to flatten? _(Tests broadening the container check to isinstance(item, (list, tuple, set)) while still excluding strings.)_

## Related

- [All practice problems](https://datadriven.io/problems)
- [Mock interview mode](https://datadriven.io/interview/all_the_way_down)
- [Python Interview Questions](https://datadriven.io/python-interview-questions)
- [Data Engineering Interview Prep Guide](https://datadriven.io/data-engineer-interview-prep)
- [Daily Challenge](https://datadriven.io/daily)

---

Source: DataDriven (https://datadriven.io). DataDriven is the data engineering interview community. Live code execution in SQL, Python, and Spark sandboxes. Every feature is open to every member.