# Single File

> However deep the nesting, every voice arrives in its own turn.

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

Domain: Python · Difficulty: easy · Seniority: L3

## Problem

A content `feed` arrives as a list whose entries are grouped into sub-lists nested to arbitrary depth; collapse it into a single flat list of leaf values in their original left-to-right order. A leaf is any non-list value, so a string stays whole rather than being split into its characters, and empty sub-lists contribute nothing.

## Worked solution and explanation

### What you are really being asked

Strip the feed costume off and this is depth-first leaf collection: walk the structure, and every value that is not itself a list is a leaf you keep, in the order you meet it. The recursion is the easy part. The thing that separates a clean pass from a quietly broken one is the type test. The tempting move is to ask 'can I iterate this?' and recurse when the answer is yes. That instinct detonates on the first string: 'tech' is perfectly iterable, so you descend into it and hand back its characters. Branch on `isinstance(item, list)` specifically and the trap never opens.

---

### Where it bites

**isinstance(item, list)**

Recurses only into real sub-lists. A string like 'tech' is not a list, so it lands in the result untouched. This is the behavior you want.

**isinstance(item, Iterable)**

Treats every iterable as nestable. 'tech' is iterable, so you recurse into it and get back 't', 'e', 'c', 'h'. The feed silently shreds every string leaf.

---

### Building it

#### Step 1: Walk one level at a time

Loop over the entries at the current depth. You do not need to know how deep the feed goes; recursion handles depth for you, so this loop only ever reasons about one level at a time.

#### Step 2: Branch on list, never on iterable

For each entry, ask only one question: is it a list? If yes, it is more structure to descend into. If no, it is a leaf (string included) and goes straight into the result. Widening this test to any-iterable is exactly how strings get shredded.

#### Step 3: Splice children in place

Recurse on a sub-list and extend the result with whatever comes back. Because you extend in iteration order, the depth-first left-to-right ordering falls out for free, with no sorting or post-processing needed.

**Recursive depth-first flattening**

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

> **Common pitfall**
>
> Reaching for `isinstance(item, Iterable)` or a try/except around `iter(item)`. Strings, bytes, and dict keys are all iterable, so any of these quietly recurses into a string and returns its characters. Test for `list` (or list and tuple if tuples count as structure) and nothing else.

> **Time and space**
>
> Time is O(n) for n total leaves: each leaf is appended exactly once. Space is O(n) for the output plus O(d) for the call stack, where d is the deepest nesting. For pathological depth (tens of thousands of levels) you would hit Python's recursion limit and switch to an explicit stack.

> **Interviewers watch for**
>
> Two tells. First, does the empty feed just work? It should: the loop never runs and you return []. No special case needed, and adding one signals you did not trust your own base case. Second, do you mention the recursion-depth ceiling before being asked?

---

## Common follow-up questions

- How would you flatten iteratively using a stack? _(Tests replacing recursion with an explicit stack for O(1) call-stack usage.)_
- What if the input can contain dicts or tuples? _(Tests broadening the type check or using a more general iterable detection.)_
- What if you needed to preserve nesting depth as metadata? _(Tests returning (value, depth) pairs instead of raw values.)_

## Related

- [All practice problems](https://datadriven.io/problems)
- [Mock interview mode](https://datadriven.io/interview/single_file)
- [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). 100% free data engineering interview prep. Live code execution against Postgres 16, Python 3.11, and Spark sandboxes. No paywall, no premium tier, no signup gate.