To flatten Python data correctly, first decide whether it is nested one level, nested arbitrarily, or stored as a multidimensional NumPy array.
Those are different problems. A one-line comprehension is excellent for a list of lists and incorrect for a tree containing strings, dictionaries, generators, and domain objects.
Table of contents
- Flatten one level with a comprehension
- Stream one level with itertools.chain
- Treat arbitrary depth as a data-model decision
- Avoid clever methods that copy repeatedly
- Know NumPy flatten, ravel, and reshape
- How this fits the rest of the stack
- FAQ
Flatten one level with a comprehension
For a known list of lists, a nested comprehension is direct and fast enough for most application code. Read it in loop order: take each group, then each item from that group.
groups = [[1, 2], [3], [4, 5]]
flat = [item for group in groups for item in group]
This eagerly creates a new list. That is ideal when the result will be reused, indexed, or serialized. If the input can be huge and the consumer needs one pass, use a lazy iterator instead.
Stream one level with itertools.chain
itertools.chain.from_iterable yields items lazily from each inner iterable. It avoids holding a second full list and works with generators as well as lists.
from itertools import chain
for item in chain.from_iterable(groups):
process(item)
The outer values still need to be iterable. Validate or normalize upstream data rather than catching a mysterious type error halfway through a production stream.
Treat arbitrary depth as a data-model decision
Recursive flattening needs a definition of what counts as a container. Strings and bytes are iterable but usually atomic. Dictionaries may mean keys, values, items, or a record that should never be flattened. A generic helper cannot guess product semantics.
def flatten(values):
for value in values:
if isinstance(value, (list, tuple)):
yield from flatten(value)
else:
yield value
Deep or adversarial nesting can exceed recursion limits. An explicit stack avoids recursive call depth, though it adds complexity. Put depth and item limits around untrusted input.
Avoid clever methods that copy repeatedly
sum(lists, []) looks compact but repeatedly builds larger lists, leading to poor scaling. reduce with list addition has the same copying problem. Prefer the comprehension or chain unless measurement proves another method is needed.
Do not optimize only the flatten operation while ignoring parsing, validation, and network transfer. Measure the whole pipeline with realistic shapes and record input size when slow requests occur.
Know NumPy flatten, ravel, and reshape
A NumPy array has shape and memory order. array.flatten() returns a copy as one dimension. ravel() returns a view when possible, while reshape(-1) expresses a desired shape and may return a view depending on layout.
import numpy as np
array = np.array([[1, 2], [3, 4]])
copy = array.flatten()
view_when_possible = array.ravel()
Choose based on mutation and ownership. A view shares underlying data, which saves memory but can produce surprising changes. A copy costs memory but gives a clear boundary.
How this fits the rest of the stack
If the flattened data feeds an API or worker, model its memory, CPU, database, storage, and traffic in the RunxBuild hosting calculator. The RunxBuild dashboard can then run that pipeline with logs and service limits visible.
Useful related references:
- Python Not Equal: != vs is not, and Why the Difference Bites
- Python Integer Division: Why // Floors and Why -7 // 2 Is -4
- Python for Websites: Where It Fits and Where It Does Not
- Python services on RunxBuild
FAQ
What is the simplest way to flatten a list of lists?
Use [item for group in groups for item in group] when nesting is exactly one level and an eager list is appropriate.
How do I flatten lazily?
Use itertools.chain.from_iterable for one level or write a generator that yields recursively for defined container types.
Why should strings be handled specially?
Strings are iterable, so a generic recursive function can split them into characters. Most data models want to treat a string as one atomic value.
Is sum with an empty list a good flatten method?
No for non-trivial data. Repeated list addition copies growing results and scales poorly compared with a comprehension or chain.
What is the difference between NumPy flatten and ravel?
flatten returns a copy. ravel returns a view when possible, so changes can share underlying array data.