Flatten an irregular arbitrarily nested list of lists
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Flattening an irregularly nested list means converting a structure like [1, [2, [3, 4], 5], [6, 7]] into [1, 2, 3, 4, 5, 6, 7]. The challenge is that nesting depth is unpredictable — some elements are values, some are lists, and those lists may contain more lists. A recursive generator is the cleanest Python solution. For regular (uniformly nested) lists, itertools.chain or list comprehensions work, but irregular nesting requires checking each element's type.
Method 1: Recursive Generator (Recommended)
yield from delegates to the recursive call, producing each element lazily. The str and bytes check prevents strings from being iterated character by character (since strings are iterable in Python).
Method 2: Recursive Function (Returns List)
Simpler but builds the entire list in memory. The generator approach is better for large datasets.
Method 3: Iterative with Stack
Avoid recursion by using an explicit stack:
reversed() ensures elements come out in the correct order when popping from the stack. This avoids Python's default recursion limit (1000 frames).
Method 4: Regular Nesting with itertools.chain
For uniformly nested lists (one level deep only):
This does NOT work for irregular nesting — chain.from_iterable only flattens one level.
Method 5: Using functools.reduce
This is O(n^2) because each + creates a new list. Avoid for large inputs.
Method 6: NumPy (Numeric Arrays Only)
NumPy requires uniform shapes and numeric types. It cannot handle irregular nesting.
Handling Mixed Types
Strings remain intact because of the isinstance(item, (str, bytes)) guard. Tuples and other iterables are flattened.
Depth-Limited Flattening
Sometimes you only want to flatten N levels deep:
Common Pitfalls
- Strings are iterable: Without the
str/bytesguard,"hello"gets split into['h', 'e', 'l', 'l', 'o'], and single characters recurse infinitely since"h"is also iterable. - Recursion depth: Python's default recursion limit is 1000. Deeply nested structures (100+ levels) cause
RecursionError. Use the iterative stack approach for untrusted input. - Dictionaries are iterable:
isinstance(dict, Iterable)isTrue. Flattening a dict yields its keys. Adddictto the exclusion check if dicts should remain intact. reduce(operator.add)is O(n^2): Each concatenation copies the entire accumulated list. For 10,000 sublists, this creates 10,000 intermediate lists. Usechain.from_iterableor a generator instead.- Generators are single-use:
flatten()withyieldreturns a generator that can only be consumed once. Wrap inlist()if you need to iterate multiple times.
Summary
- Use a recursive generator with
yield fromfor irregular nesting — it handles arbitrary depth and mixed types - Guard against strings and bytes to prevent infinite recursion on character iteration
- Use
itertools.chain.from_iterablefor simple one-level flattening - Use an iterative stack approach when recursion depth is a concern
- NumPy's
flatten()only works for regular-shaped numeric arrays - Avoid
reduce(operator.add)for large lists due to quadratic time complexity

