Perfect use case for recursion, which could handle even deeper structure:
function flatten(ary) {
var ret = [];
for(var i = 0; i < ary.length; i++) {
if(Array.isArray(ary[i])) {
ret = ret.concat(flatten(ary[i]));
} else {
ret.push(ary[i]);
}
}
return ret;
}
flatten([[[[[0]], [1]], [[[2], [3]]], [[4], [5]]]]) // [0, 1, 2, 3, 4, 5]
Alternatively, as an Array method:
Array.prototype.flatten = function() {
var ret = [];
for(var i = 0; i < this.length; i++) {
if(Array.isArray(this[i])) {
ret = ret.concat(this[i].flatten());
} else {
ret.push(this[i]);
}
}
return ret;
};
[[[[[0]], [1]], [[[2], [3]]], [[4], [5]]]].flatten() // [0, 1, 2, 3, 4, 5]
EDIT #1: Well, think it a little bit functional way (except for the named recursion which should be using Y-combinator for pure functional :D).
function flatten(ary) {
return ary.reduce(function(a, b) {
if (Array.isArray(b)) {
return a.concat(flatten(b))
}
return a.concat(b)
}, [])
}
Let's adopt some ES6 syntax which makes it even shorter, in one line.
const flatten = (ary) => ary.reduce((a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), [])
But remember, this one cannot be applied as an array method, because arrow functions don't have theirs own this.
EDIT #2: With the latest Array.prototype.flat proposal this is super easy. The array method accepts an optional parameter depth, which specifies how deep a nested array structure should be flattened (default to 1).
[[[[[0]], [1]], [[[2], [3]]], [[4], [5]]]].flat() // [[[[0]], [1]], [[[2], [3]]], [[4], [5]]]
[[[[[0]], [1]], [[[2], [3]]], [[4], [5]]]].flat(2) // [[[0]], [1], [[2], [3]], [4], [5]]
[[[[[0]], [1]], [[[2], [3]]], [[4], [5]]]].flat(3) // [[0], 1, [2], [3], 4, 5]
[[[[[0]], [1]], [[[2], [3]]], [[4], [5]]]].flat(4) // [0, 1, 2, 3, 4, 5]
So to flatten an array of arbitrary depth, just call flat method with Infinity.
[[[[[0]], [1]], [[[2], [3]]], [[4], [5]]]].flat(Infinity) // [0, 1, 2, 3, 4, 5]
Answer from Leo on Stack OverflowPerfect use case for recursion, which could handle even deeper structure:
function flatten(ary) {
var ret = [];
for(var i = 0; i < ary.length; i++) {
if(Array.isArray(ary[i])) {
ret = ret.concat(flatten(ary[i]));
} else {
ret.push(ary[i]);
}
}
return ret;
}
flatten([[[[[0]], [1]], [[[2], [3]]], [[4], [5]]]]) // [0, 1, 2, 3, 4, 5]
Alternatively, as an Array method:
Array.prototype.flatten = function() {
var ret = [];
for(var i = 0; i < this.length; i++) {
if(Array.isArray(this[i])) {
ret = ret.concat(this[i].flatten());
} else {
ret.push(this[i]);
}
}
return ret;
};
[[[[[0]], [1]], [[[2], [3]]], [[4], [5]]]].flatten() // [0, 1, 2, 3, 4, 5]
EDIT #1: Well, think it a little bit functional way (except for the named recursion which should be using Y-combinator for pure functional :D).
function flatten(ary) {
return ary.reduce(function(a, b) {
if (Array.isArray(b)) {
return a.concat(flatten(b))
}
return a.concat(b)
}, [])
}
Let's adopt some ES6 syntax which makes it even shorter, in one line.
const flatten = (ary) => ary.reduce((a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), [])
But remember, this one cannot be applied as an array method, because arrow functions don't have theirs own this.
EDIT #2: With the latest Array.prototype.flat proposal this is super easy. The array method accepts an optional parameter depth, which specifies how deep a nested array structure should be flattened (default to 1).
[[[[[0]], [1]], [[[2], [3]]], [[4], [5]]]].flat() // [[[[0]], [1]], [[[2], [3]]], [[4], [5]]]
[[[[[0]], [1]], [[[2], [3]]], [[4], [5]]]].flat(2) // [[[0]], [1], [[2], [3]], [4], [5]]
[[[[[0]], [1]], [[[2], [3]]], [[4], [5]]]].flat(3) // [[0], 1, [2], [3], 4, 5]
[[[[[0]], [1]], [[[2], [3]]], [[4], [5]]]].flat(4) // [0, 1, 2, 3, 4, 5]
So to flatten an array of arbitrary depth, just call flat method with Infinity.
[[[[[0]], [1]], [[[2], [3]]], [[4], [5]]]].flat(Infinity) // [0, 1, 2, 3, 4, 5]
ES6-style with recursion:
Redacted
June 2018 Update:
There is now an ES proposal for an Array.prototype.flat method. It is currently at stage 3, meaning it's likely to be implemented by browsers soon(ish) and make it into the spec in its current form. There are probably some polyfills floating around.
Example:
const nested = [[[0], [1]], [[2], [3]], [[4], [5]]];
const flattened = nested.flat(2); // Need to specify depth if > 1
June 2019 Update:
Array.prototype.flat was officially added to the language in the ES2019 spec.
Best Ways to Deep Flatten Arrays in JavaScript?
Flatten a nested array
How to make a flatten list function recursive? I made it iterative...
How to flatten a deep nested Array in JS
While this method works, it's... not that great. It uses a ton of memory creating new arrays with recursive concat calls. You can do it in place and iteratively on a single array, which should be much faster and less costly:
var nested = [3, [1, 'hey', [2, 'you', [2, 5]]], 1, [9, [{}, [2, true]]]];
var flat = [].concat(nested);
for(var i = 0; i < flat.length; i++) {
if(Array.isArray(flat[i])) {
flat.splice(i, 1, ...flat[i--]);
}
}
console.log(flat); More on reddit.com Videos
Flattening arrays with .flat() is simple, but handling deeply nested arrays can be tricky. What’s your go-to approach for deep flattening in JavaScript? I came across this interesting write-up with some techniques: Deep Flatten Arrays in JavaScript. https://www.interviewsvector.com/javascript/deep-flaten
Would love to hear your thoughts or see alternative methods!