众所周知,要[[0, 1], [2, 3], [4, 5]]
使用以下方法展平数组reduce()
var flattened = [[0, 1], [2, 3], [4, 5]].reduce(function(a, b) {
return a.concat(b);
});
因此,如何扁平化这个数组[[[0], [1]], [[2], [3]], [[4], [5]]]
来[0, 1, 2, 3, 4, 5]
?
众所周知,要[[0, 1], [2, 3], [4, 5]]
使用以下方法展平数组reduce()
var flattened = [[0, 1], [2, 3], [4, 5]].reduce(function(a, b) {
return a.concat(b);
});
因此,如何扁平化这个数组[[[0], [1]], [[2], [3]], [[4], [5]]]
来[0, 1, 2, 3, 4, 5]
?
递归的完美用例,它可以处理更深的结构:
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]
或者,作为 Array 方法:
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]
编辑#1:好吧,认为它有点功能性的方式(命名递归除外,它应该使用 Y-combinator 进行纯功能性:D)。
function flatten(ary) {
return ary.reduce(function(a, b) {
if (Array.isArray(b)) {
return a.concat(flatten(b))
}
return a.concat(b)
}, [])
}
让我们采用一些 ES6 语法,使其更短,在一行中。
const flatten = (ary) => ary.reduce((a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), [])
但请记住,这个不能作为数组方法应用,因为箭头函数没有自己的this
.
编辑 #2:根据最新的Array.prototype.flat
提案,这非常容易。数组方法接受一个可选参数depth
,该参数指定嵌套数组结构应展平的深度(默认为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]
因此,要展平任意深度的数组,只需flat
使用Infinity
.
[[[[[0]], [1]], [[[2], [3]]], [[4], [5]]]].flat(Infinity) // [0, 1, 2, 3, 4, 5]
ES6 风格的递归:
Redacted
2018 年 6 月更新:
现在有一个关于Array.prototype.flat
方法的 ES 提议。它目前处于第 3 阶段,这意味着它很可能很快就会被浏览器实现(ish)并以当前的形式将其纳入规范。可能有一些 polyfill 漂浮在周围。
例子:
const nested = [[[0], [1]], [[2], [3]], [[4], [5]]];
const flattened = nested.flat(2); // Need to specify depth if > 1
2019 年 6 月更新:
Array.prototype.flat
在 ES2019 规范中正式添加到该语言中。
这是递归的替代方法(请参阅此处的 jsfiddle),并且应该接受避免堆栈溢出的任何深度级别。
var array = [[0, 1], [2, 3], [4, 5, [6, 7, [8, [9, 10]]]]];
console.log(flatten(array), array); // does not mutate array
console.log(flatten(array, true), array); // array is now empty
// This is done in a linear time O(n) without recursion
// memory complexity is O(1) or O(n) if mutable param is set to false
function flatten(array, mutable) {
var toString = Object.prototype.toString;
var arrayTypeStr = '[object Array]';
var result = [];
var nodes = (mutable && array) || array.slice();
var node;
if (!array.length) {
return result;
}
node = nodes.pop();
do {
if (toString.call(node) === arrayTypeStr) {
nodes.push.apply(nodes, node);
} else {
result.push(node);
}
} while (nodes.length && (node = nodes.pop()) !== undefined);
result.reverse(); // we reverse result to restore the original order
return result;
}
ary.flat(Infinity);
而已。就这么简单。Infinity
如果您愿意,您可以更改为适当的扁平度级别。
例子:
其他适用于以下旧浏览器的更长的解决方案。
基于@Leo 的解决方案,但通过重用相同的数组并防止速度更快 .concat
function flatten(ary, ret = []) {
for (const entry of ary) {
if (Array.isArray(entry) {
flatten(entry, ret);
} else {
ret.push(entry);
}
}
return ret;
}
console.log(flatten([[[0], [1]], [[2], [3]], [[4], [5]]]));
或者使用Array.prototype.reduce
,因为你提到了它:
function flatten(ary, ret = []) {
return ary.reduce((ret, entry) => {
if (Array.isArray(entry)) {
flatten(entry, ret);
} else {
ret.push(entry);
}
return ret;
}, ret);
}
console.log(flatten([[[0], [1]], [[2], [3]], [[4], [5]]]));
ES6 单线:
function flatten(a) {
return Array.isArray(a) ? [].concat(...a.map(flatten)) : a;
}
此外,非常深的数组的非递归版本(效率不高但相当优雅)
function flatten(a) {
var queue = a.slice();
var result = [];
while(queue.length) {
let curr = queue.pop();
if(Array.isArray(curr)) {
queue.push(...curr);
}
else result.push(curr);
}
return result;
}