Implement a flatten array function
Recursively flatten a nested array. Show the recursive reduce solution, an iterative stack version (no recursion-depth limit), and mention Array.prototype.flat(Infinity) as the built-in. Discuss the depth parameter.
flatten is a classic recursion warm-up. Show you can do it three ways and know the tradeoffs.
1. Recursive with reduce (the expected answer)
function flatten(arr) {
return arr.reduce(
(acc, item) =>
Array.isArray(item)
? acc.concat(flatten(item)) // recurse into nested arrays
: acc.concat(item),
[]
);
}
flatten([1, [2, [3, [4]], 5]]); // [1, 2, 3, 4, 5]2. With a depth parameter (like the real flat())
function flatten(arr, depth = Infinity) {
return depth < 1
? arr.slice()
: arr.reduce(
(acc, item) =>
Array.isArray(item)
? acc.concat(flatten(item, depth - 1))
: acc.concat(item),
[]
);
}
flatten([1, [2, [3]]], 1); // [1, 2, [3]]3. Iterative with a stack (no recursion-depth limit)
For very deeply nested arrays, recursion can blow the call stack. An explicit stack avoids that:
function flatten(arr) {
const stack = [...arr];
const result = [];
while (stack.length) {
const next = stack.pop();
if (Array.isArray(next)) stack.push(...next); // push children back
else result.push(next);
}
return result.reverse(); // pop reverses order, so reverse back
}4. The built-in
[1, [2, [3]]].flat(Infinity); // [1, 2, 3]Array.prototype.flat(depth) exists — mention it, but interviewers want the manual implementation.
Talking points
concatvspush—concatreturns a new array (cleaner but allocates more);push(...item)mutates in place (faster).- Recursion depth — the recursive version is elegant but can stack-overflow on pathological input; the iterative stack version is bulletproof.
Array.isArray— the correct check, nottypeof(arrays are objects).
The framing
"I'd start with the recursive reduce — it's the cleanest expression of the idea. Then I'd mention two things a senior cares about: a depth parameter to match the real flat(), and an iterative stack version that won't overflow on deeply nested input. flat(Infinity) is the built-in, but the point of the exercise is the recursion."
Follow-up questions
- •How would you handle extremely deep nesting that overflows the call stack?
- •What's the difference between concat and push(...) here?
- •How does Array.prototype.flat's depth parameter work?
- •Can you flatten while also removing duplicates?
Common mistakes
- •Using typeof instead of Array.isArray to detect nested arrays.
- •Mutating the input array instead of returning a new one.
- •Forgetting that the stack/pop version reverses order.
- •Not handling the depth parameter when asked.
Performance considerations
- •concat-based recursion allocates a new array at every level — O(n) extra allocations. A push-based or stack-based version is faster and more memory-friendly for large inputs.
Edge cases
- •Empty arrays and empty nested arrays.
- •Non-array values like null or objects — should pass through untouched.
- •Extremely deep nesting causing a RangeError in the recursive version.
- •Sparse arrays with holes.
Real-world examples
- •Flattening nested category trees or comment threads into a flat list for rendering.
- •Normalizing deeply nested API responses.