Flatten a nested array with custom ordering (top-level first, then nested)
Walk the array breadth-first: emit all primitives at the current level, queue arrays to process next. This yields top-level values before deeper ones — different from `Array.prototype.flat(Infinity)` which is depth-first. Iterative BFS with a queue is the cleanest implementation.
Standard flat(Infinity) flattens depth-first — once it descends into a nested array, it emits everything inside before returning. For "top-level first, then nested" we need breadth-first ordering.
Example
flattenBFS([1, [2, [3, 4], 5], 6, [7]])
// depth-first (flat): [1, 2, 3, 4, 5, 6, 7]
// breadth-first (this): [1, 6, 2, 5, 7, 3, 4]All level-0 primitives, then level-1, then level-2, etc.
Implementation
function flattenBFS(arr) {
const out = [];
let queue = [arr];
while (queue.length) {
const next = [];
for (const node of queue) {
for (const item of node) {
if (Array.isArray(item)) next.push(item);
else out.push(item);
}
}
queue = next;
}
return out;
}Per level: emit primitives in order, defer arrays. Repeat with the deferred set. O(n) in total elements; O(w) extra space for the queue (w = widest level).
Variant: depth-first with explicit depth control
If the question instead means "flatten to N levels":
function flatN(arr, depth = Infinity, out = []) {
for (const item of arr) {
if (Array.isArray(item) && depth > 0) flatN(item, depth - 1, out);
else out.push(item);
}
return out;
}Interview framing
"flat(Infinity) is depth-first. For 'top-level first then nested' I'd do breadth-first: process the current array, emit primitives, queue any sub-arrays for the next pass. O(n) total work, iterative so no stack overflow on deep nests. If they wanted depth-first with a limit instead, that's a recursive walk with a depth counter."
Follow-up questions
- •How does this differ from Array.prototype.flat?
- •How would you handle objects that look like arrays (array-like)?
- •Iterative vs recursive — when does it matter?
Common mistakes
- •Using flat(Infinity) — that's depth-first.
- •Recursing deeply on adversarial input → stack overflow.
- •Mutating the input.
Performance considerations
- •Iterative BFS avoids stack overflow on deeply nested input. Avoid concat/spread in hot loops — push individual items.
Edge cases
- •Empty arrays and empty input.
- •Sparse arrays (holes).
- •Cycles — pass a visited Set if the input may self-reference.
Real-world examples
- •Tree → list rendering with level-priority, comment threads, file tree breadcrumbs.