You have a list of lists — [[1, 2], [3, 4], [5, 6]] — and you want one flat list: [1, 2, 3, 4, 5, 6]. There are three good ways to do it and one popular way that quietly gets slow. Here's each, when to use it, and the one mistake everyone makes.
The quick answer
The most Pythonic one-liner is a nested list comprehension:
nested = [[1, 2], [3, 4], [5, 6]]
flat = [x for row in nested for x in row]
# [1, 2, 3, 4, 5, 6]
If you don't need a list specifically — just to iterate — itertools.chain.from_iterable is the cleanest and fastest. Both are below.
1. Nested list comprehension
Read the two for clauses left to right, exactly in the order you'd write nested loops:
flat = [x for row in nested for x in row]
# the same thing as an explicit loop:
flat = []
for row in nested: # outer first
for x in row: # inner second
flat.append(x)
This is the one people reach for, and it's a great default: no imports, obvious intent.
The mistake everyone makes: clause order
The clauses go outer-loop first, inner-loop second — the same order as the nested loops — but the expression (x) goes at the front. Flip the for clauses and you get a NameError, because row isn't defined yet when the inner clause runs:
# WRONG — inner loop references `row` before it exists
flat = [x for x in row for row in nested] # NameError: name 'row' is not defined
# RIGHT — outer clause (row) comes first
flat = [x for row in nested for x in row]
Rule of thumb: write the nested for loops in your head, then move the body to the front. The loops keep their order.
2. itertools.chain.from_iterable (cleanest / fastest)
When the goal is to iterate over everything as if the sublists were one stream, this is the idiomatic tool — and it's typically the fastest because the looping happens in C:
from itertools import chain
flat = list(chain.from_iterable(nested))
# [1, 2, 3, 4, 5, 6]
# often you don't even need the list — just iterate:
for x in chain.from_iterable(nested):
print(x)
Use this when the nesting is exactly one level deep and you care about speed or readability on large inputs.
3. The sum() trap — works, but O(n²)
You'll see this clever-looking trick a lot:
flat = sum(nested, []) # works... but don't
It gives the right answer, but it builds a brand-new list on every step, so flattening n sublists copies roughly n² elements. On a handful of lists it's fine; on thousands it's dramatically slower than the comprehension or chain. Prefer those.
Flattening deeply nested lists
All three methods above flatten exactly one level. If your data is nested to arbitrary depth — [1, [2, [3, [4]]]] — you need recursion, because you don't know how deep it goes:
def flatten(items):
for x in items:
if isinstance(x, list):
yield from flatten(x) # recurse into sublists
else:
yield x
deep = [1, [2, [3, [4]]], 5]
list(flatten(deep)) # [1, 2, 3, 4, 5]
yield from makes this a clean generator — it streams values out without building intermediate lists.
Which one to use
one level, need a list -> [x for row in nested for x in row]
one level, just iterating -> chain.from_iterable(nested)
arbitrary depth -> a recursive generator (yield from)
sum(nested, []) -> avoid: O(n²)
Common gotchas
-
Strings are iterable too: if a "sublist" might be a string,
chain.from_iterableand the recursive version will split it into characters. Guard with an explicit type check (isinstance(x, list)) if that matters. -
One level only: the comprehension and
chaindon't recurse —[[1, [2]], [3]]flattens to[1, [2], 3], not[1, 2, 3]. -
NumPy arrays: if you're flattening a rectangular grid of numbers,
np.array(nested).ravel()or.flatten()is faster and clearer than any of these.
Flattening is the canonical use of a nested comprehension. If you're prepping for a Python interview, Peakblick runs mock interviews on a timer and scores every answer 1–10 with feedback — free to try, no card.
Top comments (0)