我们知道,使用[[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 :(得分:41)
递归的完美用例,可以处理更深层次的结构:
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]
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), [])
但请记住,这个不能用作数组方法,因为arrow functions没有自己的this
。
编辑#2:使用最新的Array.prototype.flat
提案,这非常简单。 array方法接受一个可选参数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]
答案 1 :(得分:40)
带递归的ES6风格:
function flatten(arr) {
const flat = [].concat(...arr);
return flat.some(Array.isArray) ? flatten(flat) : flat;
}
效率不高,所以除了相对微不足道的情况外,不要使用任何东西,但它至少看起来不错。
2018年6月更新:
现在有Array.prototype.flat
method的ES提案。它目前处于第3阶段,这意味着它可能很快就会被浏览器实现(ish),并使其成为当前形式的规范。可能有一些聚四氟乙烯漂浮在周围。
示例:
const nested = [[[0], [1]], [[2], [3]], [[4], [5]]];
const flattened = nested.flat(2); // Need to specify depth if > 1
答案 2 :(得分:31)
这是递归的替代方法( see jsfiddle here ),并且应该接受任何级别的深度,以避免堆栈溢出。
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;
}
&#13;
答案 3 :(得分:11)
ES6 one-liner:
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;
}
答案 4 :(得分:10)
基于@Leo的解决方案,但通过重复使用相同的数组并阻止.concat
function flatten(ary, ret) {
ret = ret === undefined ? [] : ret;
for (var i = 0; i < ary.length; i++) {
if (Array.isArray(ary[i])) {
flatten(ary[i], ret);
} else {
ret.push(ary[i]);
}
}
return ret;
}
示例:
function flatten(ary, ret) {
ret = ret === undefined ? [] : ret;
for (var i = 0; i < ary.length; i++) {
if (Array.isArray(ary[i])) {
flatten(ary[i], ret);
} else {
ret.push(ary[i]);
}
}
return ret;
}
console.log(flatten([[[0], [1]], [[2], [3]], [[4], [5]]]));
或者Array.prototype.reduce
,因为你提到了它:
function flatten(ary, ret) {
return ary.reduce(function(ret, entry) {
if (Array.isArray(entry)) {
flatten(entry, ret);
} else {
ret.push(entry);
}
return ret;
}, ret || []);
}
示例:
function flatten(ary, ret) {
return ary.reduce(function(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]]]));
答案 5 :(得分:7)
仅展平2个级别:
var arr = [1, [2, 3], [4, 5, 6]];
[].concat.apply([], arr) // -> [1, 2, 3, 4, 5, 6]
答案 6 :(得分:4)
我喜欢我的解决方案:)
var flattenClosure = function(a) {
var store = [];
return function() {
var internMapper = function(b) {
if (Array.isArray(b)) {
return b.map(internMapper);
}
store.push(b);
return b;
}
a.map(internMapper);
return store;
}
};
console.log(flattenClosure([[[[[[[[1]]]], [2], [4], [6, 8, 9], 2]]], 10, 11, [15, 17, 20], [], 33])());
答案 7 :(得分:4)
免责声明:我知道这是一个陈旧且已经回答过的问题,但是@Nick让我进入了它,因为我已经评论了他的答案,因为是最昂贵的平铺方式之一数组。多年来我一直没有编写JavaScript代码,但就像骑自行车一样 - 一旦你知道你永远不会忘记;)
这是我的完整递归代码(不需要var flattened = [];
function flatten(a, i) {
if(a.length > i) {
if(Array.isArray(a[i]))
flatten(a[i], 0);
else
flattened.push(a[i]);
flatten(a, i + 1);
}
}
flatten([[0, 1], [2, 3], [4, 5]], 0);
console.log(flattened);
循环):
toString().split(',')
我已经针对secitems.sections.push("Test")
return secitems
解决方案对其进行了测试,并且我的速度提高了约7倍。这就是我在谈论昂贵;)时的意思。
答案 8 :(得分:4)
受到来自Eloquent JavaScript的代码和@axelduch提供的答案的启发(从我能说的内容来说效率更高。)
function flatten(array, mutable) {
var nodes = (mutable && array) || array.slice(); // return a new array.
var flattened = [];
for (var node = nodes.shift(); node !== undefined; node = nodes.shift()) {
if (Array.isArray(node)) {
nodes.unshift.apply(nodes, node);
} else {
flattened.push(node);
}
}
return flattened;
}
答案 9 :(得分:3)
这已经回答了,但我只是在研究JS并想知道:
var array = [[[0], [1]], [[2], [3]], [[4], [5]]];
var flattend = array.join(",").split(",");
console.log(flattend);
只有副作用是联接将所有项目转换为字符串,但可以轻松修复
答案 10 :(得分:3)
function flatten(array) {
return array.reduce(
(previous, current) =>
Array.isArray(current)
? [...previous, ...flatten(current)]
: [...previous, current]
, []
);
}
答案 11 :(得分:3)
如果您知道阵列仅由数字组成,您可以执行以下操作:
array.join().split(',').map(Number);
答案 12 :(得分:2)
lodash中有三个与flatten
中的问题flatten
, flattenDeep
, flattenDepth相关的效用函数。 flattenDeep
进入一个深度,> var arr = [[[0], [1]], [[2], [3]], [[4], [5]]];
> _.flattenDeep(arr)
[0, 1, 2, 3, 4, 5]
一直进入最深层,并且展平深度让你可以选择&#34;深度&#34;扁平化。
示例:强>
{{1}}
答案 13 :(得分:2)
通过函数式编程,我们可以从另一个更通用的函数中导出flatten
:traverse
。
后者是一个遍历和减少任意嵌套数组的函数,就像平面数组一样。这是可能的,因为深度未知的嵌套数组不超过树数据结构的特定版本:
const traverse = f => g => acc => xs => {
let [leaf, stack] = xs[0][0] === undefined
? [xs[0], xs.slice(1)]
: f([]) (xs);
return stack.length
? traverse(f) (g) (g(leaf) (acc)) (stack)
: g(leaf) (acc);
};
const dfs = stack => tree => tree[0] === undefined
? [tree, stack]
: dfs(tree.length > 1 ? concat(stack) (tree.slice(1)) : stack) (tree[0]);
const concat = ys => xs => xs.concat(ys);
const flatten = f => traverse(f) (concat) ([]);
const xs = [[[1,2,3],4,5,6],7,8,[9,10,[11,12],[[13]],14],15];
console.log(flatten(dfs) (xs));
请注意,树数据结构可以先通过深度(DFS)或先通过广度(BFS)遍历。数组通常是第一顺序遍历的。
正如我所说,traverse
是一个通用的缩减函数,如针对平面数组的reduce。因此,我们也可以轻松计算所有元素的总和:
const add = y => x => x + y;
traverse(dfs) (add) (0) (xs); // 120
结论:要以功能方式展平任意嵌套数组,我们只需要一个单行:const flatten = f => traverse(f) (concat) ([]);
。所有其他涉及的功能都是通用的,并且具有一系列其他潜在的应用。这是100%的可重用性!
答案 14 :(得分:2)
var nested = [[[0], [1]], [[2], [3]], [[4], [5]]];
var flattened = [].concat.apply([],[].concat.apply([],nested));
console.log('-> flattened now: ' + flattened);
答案 15 :(得分:2)
基于dashamble的answer,但我相信这有点简单易懂:
var steamroller = function(arr) {
var result = [];
var dropHeavyObject = function(auxArr) {
var flatnd = [];
flatnd = auxArr.map(function(x) {
if(Array.isArray(x)) {
return dropHeavyObject(x);
} else {
result.push(x);
return x;
}
});
return flatnd;
};
dropHeavyObject(arr);
return result;
}
答案 16 :(得分:1)
function flatten(arrayOfArrays) {
return arrayOfArrays.reduce(function(flat, subElem) {
return flat.concat(Array.isArray(subElem) ? flatten(subElem) : subElem);
}, []);
}
var arr0 = [0, 1, 2, 3, 4];
var arr1 = [[0,1], 2, [3, 4]];
var arr2 = [[[0, 1], 2], 3, 4];
console.log(flatten(arr0)); // [0, 1, 2, 3, 4]
console.log(flatten(arr1)); // [0, 1, 2, 3, 4]
console.log(flatten(arr2)); // [0, 1, 2, 3, 4]
console.log(flatten([])); // []
答案 17 :(得分:1)
使用Lisp约定。
然而,使用.shift()和.concat()是低效的。
flatten (array) {
// get first element (car) and shift array (cdr)
var car = array.shift();
// check to see if array was empty
if (car === undefined) {
return [];
// if the first element (car) was an array, recurse on it
} else if (_.isArray(car)) {
return flatten(car).concat(flatten(array));
// otherwise, cons (concatenate) the car to the flattened version of cdr (rest of array)
} else {
return [car].concat(flatten(array))
}
}
答案 18 :(得分:1)
使用JSON.stringify
和JSON.parse
arr = JSON.parse("[" +
JSON.stringify(arr)
.replace(/[\[\]]+/g,"")
.replace(/,,/g,",") +
"]");
答案 19 :(得分:1)
function flatten(x) {
if (x.length == 0) {return []};
if (Array.isArray(x[0])) {
return flatten(x[0].concat(flatten(x.slice(1,x.length))));
}
return [].concat([x[0]], flatten(x.slice(1,x.length)));
}
以递归方式展平数组。
答案 20 :(得分:0)
var flattenWithStack = function(arr) {
var stack = [];
var flat = [];
stack.push(arr);
while(stack.length > 0) {
var curr = stack.pop();
if(curr instanceof Array) {
stack = stack.concat(curr);
} else {
flat.push(curr);
}
}
return flat.reverse();
}
非递归。基本上是dfs。
答案 21 :(得分:0)
可以像这样解决
const array = [[0, 1], [2, 3], [4, 5, [6, 7, [8, [9, 10]]]]];
const flatten(arr) => arr.reduce((acc, item) =>
acc.concat(Array.isArray(item) ? flatten(item) : item);
}, []);
console.log(flatten(array));
请注意,在深度数组的情况下,应该应用TCO
具有递归解决方案的TCO的版本
const array = [[0, 1], [2, 3], [4, 5, [6, 7, [8, [9, 10]]]]];
const flatten = (() => {
const _flatten = (acc, arr) => arr.reduce((acc, item) => acc.concat(Array.isArray(item) ? _flatten([], item) : item), acc);
return arr => _flatten([], arr);
})();
console.log(flatten(array))
答案 22 :(得分:0)
认为这个功能有效。
function flatten(arr){
return arr.reduce(function(a,b){
return [].concat(Array.isArray(a)? flatten(a) :a,Array.isArray(b)? flatten(b):b);
});
}
答案 23 :(得分:0)
继承人我所得到的:
function steamrollArray(arr) {
// the flattened array
var newArr = [];
// recursive function
function flatten(arr, newArr) {
// go through array
for (var i = 0; i < arr.length; i++) {
// if element i of the current array is a non-array value push it
if (Array.isArray(arr[i]) === false) {
newArr.push(arr[i]);
}
// else the element is an array, so unwrap it
else {
flatten(arr[i], newArr);
}
}
}
flatten(arr, newArr);
return newArr;
}
答案 24 :(得分:0)
如果你有一个无限嵌套数组,如下面的a
,这就是我要做的。
const a = [[1,2,[3]],4]
Array.prototype.flatten = (array) => {
const newArray = []
const flattenHelper = (array) => {
array.map(i => {
Array.isArray(i) ? flattenHelper(i) : newArray.push(i)
})
}
flattenHelper(a)
return newArray
}
const newArray = a.flatten()
console.log(newArray);
答案 25 :(得分:0)
前几天我遇到了这个问题并发现了一些小问题...实际上我刚刚意识到它与上一个答案非常相似,并且对上述答案的评论表明,它不适用于对象,但对于简单数字等。它运作得很好。
如果将嵌套数组作为字符串,则用逗号分隔值。然后你可以用逗号分割它以形成一个字符串。如果您需要将字符串转换为int或float,则可以运行转换每个值的新数组。
stringArray = [[0, 1], [2, 3], [4, 5]].toString().split(',');
stringArray.forEach((v,i,a) => a[i] = parseFloat(a[i]));