Flatten Nested Array
Flatten an array nested to any depth into one level, without flat().
Problem
Given an array that can contain numbers and other arrays - nested to any depth - return a new, single-level array of every number, in its original order. Do not use the built-in Array.prototype.flat().
- Keep the original left-to-right order of the values.
- Arrays can be nested to any depth.
- Empty arrays contribute nothing.
- Return a new array; do not modify the input.
- Do not use Array.prototype.flat().
- It must work for shallow and deeply nested input alike.
Examples
Approach
- An array that contains arrays is a recursive structure - each inner array is the same problem, only smaller. That is the signal to reach for recursion.
- Walk the input left to right, keeping one result array.
- If the current item is an array, flatten it with the same function and append everything it returns.
- Otherwise it is a plain value - append it as it is.
- Return the result once every item has been visited.
- Why O(n) despite a recursive call inside a loop: each value is visited exactly once, however deep it sits. The recursion divides the work; it does not repeat it.
- Space is O(n) for the result, plus O(d) of call stack, where d is the deepest level of nesting. The explicit-stack follow-up below trades that call stack for an ordinary array.
Common mistakes
- Flattening only one level. result.concat(item) opens an array once, so [1, [2, [3, 4]]] becomes [1, 2, [3, 4]] - the nested [3, 4] survives.
- Reaching for arr.flat(Infinity). It gives the right answer, but the question is asking you to implement exactly that.
- Losing the order with a stack. A stack is last in, first out, so popping [1, [2, 3], 4] naively yields 4, 3, 2, 1. Push children right to left, or reverse the result at the end.
- Very deep nesting. Each level costs one call-stack frame, and around twenty thousand levels throws a RangeError in JavaScript. The explicit stack has no such limit.
- result.push(...flattenArray(item)) on a huge inner array. Spreading passes every element as a separate argument, and around a million of them throws a RangeError. Pushing in a loop avoids it.
- Using typeof item === "array" to detect arrays. typeof reports "object" for arrays; Array.isArray(item) is the correct check.
Step through it
Pick an input and play the algorithm step by step. The highlighted line in the code follows each step, and you can edit the code to experiment.
Solution
The same approach in JavaScript, Python, and Java. Each is a complete program that prints the examples above - JavaScript runs here, so edit it and try your own input.
JavaScript solution
Output
Run code to see output...
Without recursion - an explicit stack
Replace the call stack with an ordinary array. Pop an item; if it is an array, push its children back in right-to-left order so the leftmost is popped next - that keeps the output in order without reversing at the end. It is slightly longer, but deep nesting can no longer overflow the call stack.
JavaScript solution
Output
Run code to see output...
Follow-up - flatten only to a given depth
Flatten at most depth levels and leave anything deeper nested. Pass the remaining depth down, and only open an inner array while it is above zero. This is what Array.prototype.flat(depth) does - flat() with no argument means a depth of 1.
JavaScript solution
Output
Run code to see output...
Interview questions
- 1.
What is the main technique, and what tells you to use it?
- 2.
Why is this O(n) when there is a recursive call inside a loop?
- 3.
What is the auxiliary space of the recursive version?
- 4.
How would you solve it without recursion, and why would you?
- 5.
How do you check that a value is an array in JavaScript?
- 6.
Why not just concatenate each inner array?
Quiz
- 1.
What does flattenArray([1, [2, 3], [4, [5]]]) return? A. [1, 2, 3, 4, [5]] B. [1, 2, 3, 4, 5] C. [5, 4, 3, 2, 1] D. [1, [2, 3], [4, 5]]
- 2.
Which of these checks whether item is an array? A. typeof item === "array" B. item.isArray() C. Array.isArray(item) D. item instanceof Object
- 3.
What is the main advantage of the iterative solution? A. It uses no memory B. It avoids call-stack limits C. It always uses O(1) space D. It sorts the array
- 4.
What does [1, [2, [3]]].flat() return? A. [1, 2, 3] B. [1, 2, [3]] C. [[1, 2], 3] D. [1, [2, [3]]]
- 5.
What does flattenArray([[], [1], [], [[2]]]) return?
Comments
Sign in to leave a comment. Your name and photo come from Google; nothing else is shared.
Loading comments...
AI
System Design
Backend
- GraphQL8 modules · 69 lessons planned
- Core Python13 modules · 75 lessons planned
- FastAPI5 sections · 20 lessons
- Node.js14 modules · 206 lessons planned
- Node.js Performance7 chapters · 36 topics
- Event Loop Lifecycle6 phases · 3 scenarios
- Docker & Containerization11 modules · 144 lessons planned
- AWS for Developers14 modules · 219 lessons planned
- CI/CD & DevOps Automation10 modules · 134 lessons planned