在JavaScript中合并/拼合数组数组?
我有一个JavaScript数组,如:
[["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]
我将如何去做这个只是:
["$6", "$12", "$25", ...]
你可以使用concat
来合并数组:
var arrays = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]; var merged = [].concat.apply([], arrays);
使用concat
的apply
方法将第二个参数作为一个数组,所以最后一行是相同的:
var merged2 = [].concat(["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]);
这是一个简短的函数,它使用了一些新的JavaScript数组方法来压扁n维数组。
function flatten(arr) { return arr.reduce(function (flat, toFlatten) { return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten); }, []); }
用法:
flatten([[1, 2, 3], [4, 5]]); // [1, 2, 3, 4, 5] flatten([[[1, [1.1]], 2, 3], [4, 5]]); // [1, 1.1, 2, 3, 4, 5]
这是一个简单而高效的function解决scheme:
var result = [].concat.apply([], [[1],[2,3],[4]]); console.log(result); // [ 1, 2, 3, 4 ]
这可以通过JavaScript减lessfunction来完成。
var arrays = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"], ["$0"], ["$15"],["$3"], ["$75"], ["$5"], ["$100"], ["$7"], ["$3"], ["$75"], ["$5"]]; arrays = arrays.reduce(function(a, b){ return a.concat(b); }, []);
或者,用ES2015:
arrays = arrays.reduce((a, b) => a.concat(b), []);
JS-小提琴
Mozilla文档
更新:事实certificate,这个解决scheme不适用于大型数组。 它正在寻找一个更好,更快的解决scheme,看看这个答案 。
function flatten(arr) { return [].concat(...arr) }
简单地展开arr
并将其作为parameter passing给concat()
,它将所有数组合并成一个。 它相当于[].concat.apply([], arr)
。
你也可以尝试这个深度扁平化:
function deepFlatten(arr) { return flatten( // return shalowly flattened array arr.map(x=> // with each x in array Array.isArray(x) // is x an array? ? deepFlatten(x) // if yes, return deeply flattened x : x // if no, return just x ) ) }
在JSBin上查看演示。
本答案中使用的ECMAScript 6元素参考:
- 传播运营商
- 箭头function
注意:所有浏览器都不支持find()
和arrow函数等方法,但这并不意味着您现在不能使用这些function。 只要使用Babel – 它将ES6代码转换成ES5。
你可以使用下划线 :
var x = [[1], [2], [3, 4]]; _.flatten(x); // => [1, 2, 3, 4]
更一般情况下的解决scheme,当您的数组中可能有一些非数组元素。
function flattenArrayOfArrays(a, r){ if(!r){ r = []} for(var i=0; i<a.length; i++){ if(a[i].constructor == Array){ r.concat(flattenArrayOfArrays(a[i], r)); }else{ r.push(a[i]); } } return r; }
这里的大多数答案不适用于巨大的(如20万个元素)数组,即使他们这样做,他们也很慢。 polkovnikov.ph的答案有最好的performance,但它不适用于深展平。
这是最快的解决scheme,它也适用于具有多层嵌套的arrays :
const flatten = function(arr, result = []) { for (let i = 0, length = arr.length; i < length; i++) { const value = arr[i]; if (Array.isArray(value)) { flatten(value, result); } else { result.push(value); } } return result; };
我不认为需要解释; 任何具有JavaScript基础知识的人都应该能够理解它。
例子
巨大的数组
flatten(Array(200000).fill([1]));
它处理巨大的数组就好了。 在我的机器上,这个代码需要大约30毫秒才能执行。
嵌套数组
flatten(Array(2).fill(Array(2).fill(Array(2).fill([1]))));
它适用于嵌套数组。 此代码产生[1, 1, 1, 1, 1, 1, 1, 1]
。
具有不同层次的嵌套的数组
flatten([1, [1], [[1]]]);
它没有任何问题,像这样压扁数组。
通用程序意味着我们不必在每次需要使用特定行为时重写复杂性。
concatMap
(或flatMap
)正是我们在这种情况下所需要的。
// concat :: ([a],[a]) -> [a] const concat = (xs,ys) => xs.concat (ys) // concatMap :: (a -> [b]) -> [a] -> [b] const concatMap = f => xs => xs.map(f).reduce(concat, []) // id :: a -> a const id = x => x // flatten :: [[a]] -> [a] const flatten = concatMap (id) // your sample data const data = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]] console.log (flatten (data))
function风格的另一个ECMAScript 6解决scheme:
声明函数:
const flatten = arr => arr.reduce( (a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), [] );
并使用它:
flatten( [1, [2,3], [4,[5,[6]]]] ) // -> [1,2,3,4,5,6]
怎么样使用JavaScript 1.8
reduce(callback[, initialValue])
方法JavaScript 1.8
list.reduce( function( p,n){ return p.concat( n ); },[]);
请注意:当使用Function.prototype.apply
( [].concat.apply([], arrays)
)或spread运算符( [].concat(...arrays)
)来平整数组时,两者都可以导致大型数组的堆栈溢出,因为函数的每个参数都存储在堆栈中。
这是一个function风格的堆栈安全的实现,它将权衡最重要的需求:
- 可重用性
- 可读性
- 简明
- 性能
// small, reusable auxiliary functions: const foldl = f => acc => xs => xs.reduce(uncurry(f), acc); // aka reduce const uncurry = f => (a, b) => f(a) (b); const concat = xs => y => xs.concat(y); // the actual function to flatten an array - a self-explanatory one-line: const flatten = xs => foldl(concat) ([]) (xs); // arbitrary array sizes (until the heap blows up :D) const xs = [[1,2,3],[4,5,6],[7,8,9]]; console.log(flatten(xs)); // Deriving a recursive solution for deeply nested arrays is trivially now // yet more small, reusable auxiliary functions: const map = f => xs => xs.map(apply(f)); const apply = f => a => f(a); const isArray = Array.isArray; // the derived recursive function: const flattenr = xs => flatten(map(x => isArray(x) ? flattenr(x) : x) (xs)); const ys = [1,[2,[3,[4,[5],6,],7],8],9]; console.log(flattenr(ys));
要扁平化一个单元素数组的数组,您不需要导入一个库,简单的循环既是最简单也是最有效的解决scheme:
for (var i = 0; i < a.length; i++) { a[i] = a[i][0]; }
对downvoters:请阅读这个问题,不要downvote,因为它不适合你非常不同的问题。 这个解决scheme对于被问的问题来说是最快和最简单的。
var arrays = [["a"], ["b", "c"]]; Array.prototype.concat.apply([], arrays); // gives ["a", "b", "c"]
(根据@danhbear的评论,我只是把它写成一个单独的答案。)
看起来这看起来像RECURSION的工作!
- 处理多层次的嵌套
- 处理空数组和非数组参数
- 没有突变
- 不依赖于现代浏览器function
码:
var flatten = function(toFlatten) { var isArray = Object.prototype.toString.call(toFlatten) === '[object Array]'; if (isArray && toFlatten.length > 0) { var head = toFlatten[0]; var tail = toFlatten.slice(1); return flatten(head).concat(flatten(tail)); } else { return [].concat(toFlatten); } };
用法:
flatten([1,[2,3],4,[[5,6],7]]); // Result: [1, 2, 3, 4, 5, 6, 7]
我使用recursion和闭包来完成它
function flatten(arr) { var temp = []; function recursiveFlatten(arr) { for(var i = 0; i < arr.length; i++) { if(Array.isArray(arr[i])) { recursiveFlatten(arr[i]); } else { temp.push(arr[i]); } } } recursiveFlatten(arr); return temp; }
我宁愿将整个数组原样转换为string,但与其他答案不同,将使用JSON.stringify
而不使用toString()
方法,从而产生不需要的结果。
使用该JSON.stringify
输出,剩下的就是删除所有的括号,再将结果用开始和结束括号括起来,然后用JSON.parse
提供结果,使string回到“life”。
- 可以处理无限的嵌套数组,而无需任何速度成本。
- 可以正确处理包含逗号的string的数组项目。
var arr = ["abc",[[[6]]],["3,4"],"2"]; var s = "[" + JSON.stringify(arr).replace(/\[|]/g,'') +"]"; var flattened = JSON.parse(s); console.log(flattened)
var arr = ["abc",[[[6]]],["3,4"],"2"]; var s = "[" + JSON.stringify(arr).replace(/\[|]/g,'') +"]"; var flattened = JSON.parse(s); console.log(flattened)
如果你只有1个string元素的数组:
[["$6"], ["$12"], ["$25"], ["$25"]].join(',').split(',');
会做这项工作。 Bt特别匹配你的代码示例。
这并不难,只需遍历数组并合并它们即可:
var result = [], input = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"]]; for (var i = 0; i < input.length; ++i) { result = result.concat(input[i]); }
只是最好的解决scheme没有lodash
let flatten = arr => [].concat.apply([], arr.map(item => Array.isArray(item) ? flatten(item) : item))
我有一天在和ES6发电机打交道 ,写了这个要点 。 其中包含…
function flatten(arrayOfArrays=[]){ function* flatgen() { for( let item of arrayOfArrays ) { if ( Array.isArray( item )) { yield* flatten(item) } else { yield item } } } return [...flatgen()]; } var flatArray = flatten([[1, [4]],[2],[3]]); console.log(flatArray);
基本上我创build一个循环的原始input数组的发生器,如果它发现一个数组它使用yield *运算符结合recursion来不断扁平化内部数组。 如果该项目不是一个数组,它只是产生单个项目。 然后使用ES6 Spread运算符 (aka splat运算符),将生成器平铺到新的数组实例中。
我没有testing过这个的性能,但我认为这是一个很好的使用generator和yield *运算符的简单例子。
但是,再次,我只是蠢蠢欲动,所以我确信有更多高性能的方法来做到这一点。
这里的逻辑是将input数组转换为string,并删除所有括号([])并将输出parsing为数组。 我正在使用ES6模板function。
var x=[1, 2, [3, 4, [5, 6,[7], 9],12, [12, 14]]]; var y=JSON.parse(`[${JSON.stringify(x).replace(/\[|]/g,'')}]`); console.log(y)
Haskellesque方法
function flatArray([x,...xs]){ return x ? [...Array.isArray(x) ? flatArray(x) : [x], ...flatArray(xs)] : []; } var na = [[1,2],[3,[4,5]],[6,7,[[[8],9]]],10]; fa = flatArray(na); console.log(fa);
对于现代浏览器来说,这是又一次深刻的变革:
function flatten(xs) { xs = Array.prototype.concat.apply([], xs); return xs.some(Array.isArray) ? flatten(xs) : xs; };
如果你的数组只包含整数或string,你可以使用这个肮脏的黑客:
var arr = [345,2,[34],2,[524,[5456]],[5456]]; var flat = arr.toString().split(',');
作品在FF,IE和Chrome还没有testing其他浏览器。
I'm aware that this is hacky, but the must succinct way I know of to flatten an array(of any depth!) of strings(without commas!) is to turn the array into a string and then split the string on commas:
var myArray =[["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"], ["$0"], ["$15"],["$3"], ["$75"], ["$5"], ["$100"], ["$7"], ["$3"], ["$75"], ["$5"]]; var myFlatArray = myArray.toString().split(','); myFlatArray; // ["$6", "$12", "$25", "$25", "$18", "$22", "$10", "$0", "$15", "$3", "$75", "$5", "$100", "$7", "$3", "$75", "$5"]
This should work on any depth of nested arrays containing only strings and numbers(integers and floating points) with the caveat that numbers will be converted to strings in the process. This can be solved with a little mapping:
var myArray =[[[1,2],[3,4]],[[5,6],[7,8]],[[9,0]]]; var myFlatArray = myArray.toString().split(',').map(function(e) { return parseInt(e); }); myFlatArray; // [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
To flatten a two-dimensional array in one line:
[[1, 2], [3, 4, 5]].reduce(Function.prototype.apply.bind(Array.prototype.concat)) // => [ 1, 2, 3, 4, 5 ]
I propose two short solutions without recursion. They are not optimal from a computational complexity point of view, but work fine in average cases:
let a = [1, [2, 3], [[4], 5, 6], 7, 8, [9, [[10]]]]; // Solution #1 while (a.find(x => Array.isArray(x))) a = a.reduce((x, y) => x.concat(y), []); // Solution #2 let i = a.findIndex(x => Array.isArray(x)); while (i > -1) { a.splice(i, 1, ...a[i]); i = a.findIndex(x => Array.isArray(x)); }
const flatten = array => array.reduce((a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []);
Per request, Breaking down the one line is basically having this.
function flatten(array) { // reduce traverses the array and we return the result return array.reduce(function(acc, b) { // if is an array we use recursion to perform the same operations over the array we found // else we just concat the element to the accumulator return acc.concat( Array.isArray(b) ? flatten(b) : b); }, []); // we initialize the accumulator on an empty array to collect all the elements }
I recommend a space-efficient generator function :
function* flatten(arr) { if (!Array.isArray(arr)) yield arr; else for (let el of arr) yield* flatten(el); } // Example: console.log(...flatten([1,[2,[3,[4]]]])); // 1 2 3 4