Foundations
Flatten Nested List
Recursively flatten a list of integers and sublists to any depth - if an element is a list, recurse into it; if it is a value, collect it.
Problem
Configuration parsers and data pipeline schemas often receive inputs with variable-depth nesting - a list where each element is either a value or another (possibly nested) list. Flattening to a single level is a prerequisite for most downstream processing. Given a nested list of integers (to any depth), return a flat list containing all integers in their original left-to-right order.
Example 1:
Input: nestedList = [4, [5, 6], [7, [8, 9]], 10]
Output: [4, 5, 6, 7, 8, 9, 10]
Explanation: nested sublists are recursively unwrapped while the left-to-right order is preserved.Example 2:
Input: nestedList = [[2, [3]], [4, [5, [6]]]]
Output: [2, 3, 4, 5, 6]Example 3:
Input: nestedList = []
Output: []
Explanation: an empty list flattens to an empty list.Example 4:
Input: nestedList = [8, 9, 10]
Output: [8, 9, 10]
Explanation: an already-flat list is returned unchanged.Constraints:
1 <= nestedList.length <= 1000- Elements are integers or lists; elements of sublists are integers or lists.
-50 <= element <= 50- The total number of elements across all nesting levels is at most
10^4.
Solution Breakdown
Approach: Structural recursion that mirrors the nesting - recurse on lists, collect plain values.
The function walks the list left to right and asks one question per element: is it a list or a plain value? isinstance(element, list) makes the distinction. A plain value is the base case - it is appended directly to result with no further recursion. A sub-list is the recursive case - flatten(element) returns a fully flat list of everything inside it, and result.extend(...) merges those items into result in order. The choice of extend over append is the crux: extend unwraps the returned list and adds its items one by one, while append would insert the whole flat list as a single nested element, re-introducing the nesting you just removed. Because the recursion descends one call per nesting level, the code's depth automatically matches the data's depth, however irregular - no manual stack or depth tracking is needed.
Trace flatten([4, [5, 6], 10]): 4 is not a list, append -> [4]; [5, 6] is a list, recurse - that call appends 5 then 6 and returns [5, 6], which extend merges -> [4, 5, 6]; 10 is not a list, append -> [4, 5, 6, 10]. Left-to-right iteration preserves original order at every level.
Edge cases: An empty list returns [] because the loop body never runs. An already-flat list appends every element directly. Arbitrarily deep single-element nests like [[[9]]] simply recurse one extra level each, reaching the integer at the bottom.
Complexity: O(n) time, O(n + d) space - every one of n elements is visited once; the output holds n items and the call stack reaches d frames deep, where d is the maximum nesting depth (worst case d = n).
Done reading? Mark it so it sticks in your dashboard.