如何在javascript中嵌套数组?

我们知道,通过使用reduce()方法来reduce()数组[[0, 1], [2, 3], [4, 5]]

 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]

这是recursion的替代方法( 请参阅这里的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; } 

recursion的完美用例,可以处理更深的结构:

 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.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的方式(除了命名recursion,应该使用纯function的Y-组合):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

ES6风格的recursion:

 function flatten(arr) { const flat = [].concat(...arr); return flat.some(Array.isArray) ? flatten(flat) : flat; } 

不是那么高效,所以不要用于任何比较微不足道的事情,但是至less看起来还不错。

基于.concat的解决scheme,但通过重复使用相同的数组和更快的防止.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]]])); 

ES6单行:

 function flatten(a) { return Array.isArray(a) ? [].concat(...a.map(flatten)) : a; } 

此外,非recursion版本非常深的数组(不是非常有效,但相当优雅)

 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; } 

只能展平2个级别:

 var arr = [1, [2, 3], [4, 5, 6]]; [].concat.apply([], arr) // -> [1, 2, 3, 4, 5, 6] 

免责声明 :我知道这是一个已经回答老的问题,但@Nick已经把我引入了它,因为我已经把他的答案评论为扁平化数组最昂贵的方法之一 。 我多年来一直没有编写JavaScript,但它就像骑自行车 – 一旦你学会了,你将永远不会忘记;)

这是我的完整的recursion代码(没有for循环需要):

 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); 

我已经testing了toString().split(',')解决scheme,我的速度提高了7倍。 这就是我说的昂贵的意思;)

我喜欢我的解决scheme:)

 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])()); 

灵感来自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; } 
 function flatten(array) { return array.reduce( (previous, current) => Array.isArray(current) ? [...previous, ...flatten(current)] : [...previous, current] , [] ); } 

如果您知道该arrays仅由数字组成,则可以执行以下操作:

 array.join().split(',').map(Number); 

具有函数式编程的实现

通过函数式编程,我们可以简单地从另一个更通用的函数中导出: traverse

后者是一个像平面数组一样遍历和减less任意嵌套数组的函数。 这是可能的,因为具有未知深度的嵌套数组不超过特定版本的树数据结构:

 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)); 

这已经回答了,但我只是在研究JS,想知道如何:

  var array = [[[0], [1]], [[2], [3]], [[4], [5]]]; var flattend = array.join(",").split(","); console.log(flattend); 

只有副作用是联接将所有项目转换为string,但可以很容易地修复

lodash中有三个与你的问题相关的效用函数flattenflattenDeep ,flattenDepth in lodashflatten成一个单一的深度, flattenDeep进入最深层次和flattenDepth给你“多深”的select平坦的select。

例:

 > var arr = [[[0], [1]], [[2], [3]], [[4], [5]]]; > _.flattenDeep(arr) [0, 1, 2, 3, 4, 5] 
 var nested = [[[0], [1]], [[2], [3]], [[4], [5]]]; var flattened = [].concat.apply([],[].concat.apply([],nested)); console.log('-> flattened now: ' + flattened); 
 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))); } 

recursion地展平数组。

基于达斯汉布尔的回答 ,但我相信这是一个更简单的理解:

 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; } 

使用JSON.stringifyJSON.parse

 arr = JSON.parse("[" + JSON.stringify(arr) .replace(/[\[\]]+/g,"") .replace(/,,/g,",") + "]"); 
 // implementation function flattenArray(){ const input = arguments[0] , output = flatten(input) function flatten(){ return [].concat.apply([], arguments[0]) } return input.length === output.length ? output : flattenArray(output) } // how to use? flattenArray([1,2,[3]) // return [1,2,3] 

testing用例 – > https://github.com/CHAOWEICHIU/ccw-custom-functions/blob/master/test/units/flattenArray.js

 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([])); // [] 

使用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)) } } 

我有这个问题有一天,发现了一点点黑客…其实我刚刚意识到这是非常相似的最后一个答案,像上面的答案的评论表明,它不会用于对象,但对于简单的数字等它工作得很好。

如果你把一个嵌套的数组作为string,它将用逗号分隔这些值。 然后你可以用逗号分隔它来形成一个string。 如果您需要将string转换为int或float,则可以通过转换每个值的新数组来运行。

 stringArray = [[0, 1], [2, 3], [4, 5]].toString().split(','); stringArray.forEach((v,i,a) => a[i] = parseFloat(a[i])); 

如果你有一个像下面这样的无限嵌套数组,下面是我要做的。

 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); 

下面是我得到的:

 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; } 

可以这样解决

 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)); 

请注意,如果是深度arrays,则应使用TCO

带有recursion解决scheme的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)) 
 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(); } 

非recursion。 基本上dfs。

认为这个function起作用。

  function flatten(arr){ arr = arr.reduce(function(a,b){ return [].concat(Array.isArray(a)? flatten(a) :a,Array.isArray(b)? flatten(b):b); }); return arr; }