Here is one way:
var input = [1, {a: 2}, [3], [[4, 5], 6], 7]; function flatten(input) { var i, placeHolder = [input], lastIndex = [-1], out = []; while (placeHolder.length) { input = placeHolder.pop(); i = lastIndex.pop() + 1; for (; i < input.length; ++i) { if (Array.isArray(input[i])) { placeHolder.push(input); lastIndex.push(i); input = input[i]; i = -1; } else out.push(input[i]); } } return out; } flatten(input);
Explanation:. If you iterate over a nested structure, you just need to remember where you were, keeping the current array and position before moving into the nested array (this is usually taken care of through the stack for recursive solutions).
Note. If you reuse placeHolder and lastIndex arrays, you wonβt need to recreate them all the time. Maybe something like this:
var flatten = function(){ var placeHolder = [], lastIndex = []; placeHolder.count = 0; lastIndex.count = 0; return function flatten(input) { var i, out = []; placeHolder[0] = input; placeHolder.count = 1; lastIndex[0] = -1; lastIndex.count = 1; while (placeHolder.count) { input = placeHolder[--placeHolder.count]; i = lastIndex[--lastIndex.count] + 1; for (; i < input.length; ++i) { if (Array.isArray(input[i])) { placeHolder[placeHolder.count++] = input; lastIndex[lastIndex.count++] = i; input = input[i]; i = -1; } else out.push(input[i]); } } return out; } }();
This is even faster (for a flat iteration), and fewer problems with garbage collectors causes it many times. The speed is very close to the speed of calling a recursive function in Chrome and is many times faster than the recursion in FireFox and IE.
I recreated Tomalak tests here, as the old jsPerf is broken for editing: https://jsperf.com/iterative-array-flatten-2
James wilkins
source share