合并/展平数组数组

我有一个JavaScript数组,如:

[["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]

我将如何将单独的内部数组合并为一个:

["$6", "$12", "$25", ...]
1137445 次浏览

ES2019

ES2019引入了#0方法,您可以使用它来展平数组。它与大多数环境兼容,尽管它仅在从版本11开始的Node.js中可用,而在Internet Explorer中根本不可用。

const arrays = [["$6"],["$12"],["$25"],["$25"],["$18"],["$22"],["$10"]];const merge3 = arrays.flat(1); //The depth level specifying how deep a nested array structure should be flattened. Defaults to 1.console.log(merge3);


旧浏览器

对于较旧的浏览器,您可以使用#0合并数组:

var arrays = [["$6"],["$12"],["$25"],["$25"],["$18"],["$22"],["$10"]];var merged = [].concat.apply([], arrays);
console.log(merged);

使用concatapply方法只会将第二个参数作为数组,所以最后一行与此相同:

var merged = [].concat(["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]);

要展平单元素数组的数组,您不需要导入库,简单的循环既是最简单的,也是最有效的解决方案:

for (var i = 0; i < a.length; i++) {a[i] = a[i][0];}

给反对者:请阅读问题,不要反对者,因为它不适合你非常不同的问题。这个解决方案是最快和最简单的问题。

这并不难,只需迭代数组并合并它们:

var result = [], input = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"]];
for (var i = 0; i < input.length; ++i) {result = result.concat(input[i]);}

您可以使用下划线

var x = [[1], [2], [3, 4]];
_.flatten(x); // => [1, 2, 3, 4]

如果您只有具有1个字符串元素的数组:

[["$6"], ["$12"], ["$25"], ["$25"]].join(',').split(',');

将完成这项工作。与您的代码示例特别匹配的Bt。

这是一个简短的函数,它使用一些较新的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]

有一个令人困惑的隐藏方法,它在不改变原始数组的情况下构造一个新数组:

var oldArray = [[1],[2,3],[4]];var newArray = Array.prototype.concat.apply([], oldArray);console.log(newArray); // [ 1, 2, 3, 4 ]

如何使用JavaScript 1.8reduce(callback[, initialValue])方法

list.reduce((p,n) => p.concat(n),[]);

会做这项工作。

更一般情况下的解决方案,当您的数组中可能有一些非数组元素时。

function flattenArrayOfArrays(a, r){if(!r){ r = []}for(var i=0; i<a.length; i++){if(a[i].constructor == Array){flattenArrayOfArrays(a[i], r);}else{r.push(a[i]);}}return r;}

最好通过JavaScript Reduce函数来完成。

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-fiddle

Mozilla文档

[1,[2,3],[4,[5,6]]].reduce(function(p, c) {return p.concat(c instanceof Array ?c.reduce(arguments.callee, []) :[c]);}, []);

这是现代浏览器的另一个深度扁平化:

function flatten(xs) {xs = Array.prototype.concat.apply([], xs);return xs.some(Array.isArray) ? flatten(xs) : xs;};

如果你的数组只包含整数或字符串,你可以使用这个肮脏的黑客:

var arr = [345,2,[34],2,[524,[5456]],[5456]];var flat = arr.toString().split(',');

作品,在FF,IE和Chrome还没有测试其他浏览器。

这是我的版本。它允许你展平一个复杂的对象,可以在更多场景中使用:

输入

var input = {a: 'asdf',b: [1,2,3],c: [[1,2],[3,4]],d: {subA: [1,2]}}

代码

函数是这样的:

function flatten (input, output) {
if (isArray(input)) {for(var index = 0, length = input.length; index < length; index++){flatten(input[index], output);}}else if (isObject(input)) {for(var item in input){if(input.hasOwnProperty(item)){flatten(input[item], output);}}}else {return output.push(input);}};
function isArray(obj) {return Array.isArray(obj) || obj.toString() === '[object Array]';}
function isObject(obj) {return obj === Object(obj);}

用法

var output = []
flatten(input, output);

产出

["asdf",1,2,3,1,2,3,4,1,2]

这看起来像是回归的工作!

  • 处理多个级别的嵌套
  • 处理空数组和非数组参数
  • 没有突变
  • 不依赖现代浏览器功能

代码:

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]

什么是深度扁平化和面向对象?

[23, [34, 454], 12, 34].flatten();// -->   [23,34, 454, 12, 34]

[23, [34, 454,[66,55]], 12, 34].flatten();
// -->  [23, 34, 454, [66,55], 12, 34]

深度扁平化:

[23, [34, 454,[66,55]], 12, 34].flatten(true);
// --> [23, 34, 454, 66, 55, 12, 34]

DEMO

CDN


如果所有数组元素都是整数、浮点数、…或/和字符串,那么只需做这个技巧:

var myarr=[1,[7,[9.2]],[3],90];eval('myarr=['+myarr.toString()+']');print(myarr);// [1, 7, 9.2, 3, 90]

演示

在一行中展平二维数组:

[[1, 2], [3, 4, 5]].reduce(Function.prototype.apply.bind(Array.prototype.concat))// => [ 1, 2, 3, 4, 5 ]

使用那里的代码。

我会写:

myArray.enumerable().selectMany(function(x) { return x; }).array()

有一种比使用上面答案中列出的merge.concat.apply()方法更快的方法,更快的意思是比几个数量级更快。这假设您的环境可以访问ES5数组方法。

var array2d = [["foo", "bar"],["baz", "biz"]];merged = array2d.reduce(function(prev, next) {return prev.concat(next);});

下面是jspef链接:http://jsperf.com/2-dimensional-array-merge

我知道这很老套,但我所知道的将字符串(没有逗号!)的数组(任何深度!)展平的必须简洁的方法是将数组转换为字符串,然后在逗号上拆分字符串:

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"]

这应该适用于仅包含字符串和数字(整数和浮点数)的嵌套数组的任何深度,但需要注意的是,数字将在过程中转换为字符串。这可以通过一点映射来解决:

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]

我已经使用递归和闭包完成了

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

如果您需要支持IE8,因此不能使用Reduce或isArray等方法,这里有一个可能的解决方案。这是一种帮助您理解递归算法的冗长方法。

function flattenArray(a){
var aFinal = [];
(function recursiveArray(a){
var i,iCount = a.length;
if (Object.prototype.toString.call(a) === '[object Array]') {for (i = 0; i < iCount; i += 1){recursiveArray(a[i]);}} else {aFinal.push(a);}
})(a);
return aFinal;
}
var aMyArray = [6,3,4,[12,14,15,[23,24,25,[34,35],27,28],56],3,4];
var result = flattenArray(aMyArray);
console.log(result);

我认为最好的方法是这样的:

var flatten = function () {return [].slice.call(arguments).toString().split(',');};

更新:事实证明此解决方案不适用于大型数组。如果您正在寻找更好、更快的解决方案,请查看此答案


function flatten(arr) {return [].concat(...arr)}

is简单地扩展arr并将其作为参数传递给concat(),后者将所有数组合并为一个。它等效于[].concat.apply([], arr)

您也可以尝试深度扁平化:

function deepFlatten(arr) {return flatten(           // return shalowly flattened arrayarr.map(x=>             // with each x in arrayArray.isArray(x)      // is x an array?? deepFlatten(x)    // if yes, return deeply flattened x: x                 // if no, return just x))}

请参阅演示JSBin

本答案中使用的ECMAScript 6元素的参考:


附注:并非所有浏览器都支持find()和箭头函数等方法,但这并不意味着您现在不能使用这些功能。只需使用巴别塔-它将ES6代码转换为ES5。

如今,最好和最简单的方法是像这样连接和拆分数组。

var multipleArrays = [["$6","$Demo"], ["$12",["Multi","Deep"]], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"], ["$0"], ["$15"],["$3"], ["$75"], ["$5"], ["$100"], ["$7"], ["$3"], ["$75"], ["$5"]]
var flattened = multipleArrays.join().split(",")

此解决方案适用于多个级别,也是单线的。

演示

ECMAScript 6的编辑

由于ECMAScript 6已经标准化,您可以更改[].concat(...arrays);的操作[].concat.apply([], arrays);

var flattened = [].concat(...input);

演示

编辑最有效的解决方案

解决这个问题最有效的方法是使用循环。你可以比较“ops/sec”速度这里

var flattened=[];for (var i=0; i<input.length; ++i) {var current = input[i];for (var j=0; j<current.length; ++j)flattened.push(current[j]);}

演示

希望有帮助

前几天我在玩弄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);

基本上,我正在创建一个在原始输入数组上循环的生成器,如果它找到一个数组,它将使用产量*运算符结合递归来不断展平内部数组。如果该项目不是数组,它只是产生单个项目。然后使用ES6传播运算符(又名spat运算符)将生成器展平为一个新的数组实例。

我还没有测试它的性能,但我认为这是一个使用生成器和产量*运算符的很好的简单示例。

但同样,我只是在开玩笑,所以我相信有更有效的方法来做到这一点。

var arrays = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"], ["$0"], ["$15"],["$3"], ["$75"], ["$5"], ["$100"], ["$7"], ["$3"], ["$75"], ["$5"]];var merged = [].concat.apply([], arrays);alert(merged);

另一个函数式的ECMAScript 6解决方案:

声明一个函数:

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]

 const flatten = arr => arr.reduce((a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []);

console.log( flatten([1, [2,3], [4,[5],[6,[7,8,9],10],11],[12],13]) )

还要考虑在最新版本的现代浏览器中可用的本机函数Array.prototype.flat()(ES6提案)。感谢 @(Константин Ван) 和@(马克·阿梅里)在评论中提到了这一点。

flat函数有一个参数,指定数组嵌套的预期深度,默认情况下等于1

[1, 2, [3, 4]].flat();                  // -> [1, 2, 3, 4]
[1, 2, [3, 4, [5, 6]]].flat();          // -> [1, 2, 3, 4, [5, 6]]
[1, 2, [3, 4, [5, 6]]].flat(2);         // -> [1, 2, 3, 4, 5, 6]
[1, 2, [3, 4, [5, 6]]].flat(Infinity);  // -> [1, 2, 3, 4, 5, 6]

let arr = [1, 2, [3, 4]];
console.log( arr.flat() );
arr =  [1, 2, [3, 4, [5, 6]]];
console.log( arr.flat() );console.log( arr.flat(1) );console.log( arr.flat(2) );console.log( arr.flat(Infinity) );

Array.prototype.flatten = Array.prototype.flatten || function() {return [].reduce.call(this, function(flat, toFlatten) {return flat.concat(Array.isArray(toFlatten) ? toFlatten.flatten() : toFlatten);},[])};

我只是在寻找更快更简单的解决方案,为什么?因为我把这个作为一个面试问题,我很好奇,所以我做了这个:

function flattenArrayOfArrays(a, r){if(!r){ r = []}for(var i=0; i<a.length; i++){if(a[i].constructor == Array){flattenArrayOfArrays(a[i], r);}else{r.push(a[i]);}}return r;}
var i = [[1,2,[3]],4,[2,3,4,[4,[5]]]], output;
// Start timing nowconsole.time("flatten");output = new Array(JSON.stringify(i).replace(/[^\w\s,]/g,""));output// ... and stop.console.timeEnd("flatten");
// Start timing nowconsole.time("flatten2");output = [].concat.apply([], i)output// ... and stop.console.timeEnd("flatten2");
// Start timing nowconsole.time("flatten3");output = flattenArrayOfArrays(i)output// ... and stop.console.timeEnd("flatten3");

我使用了最受欢迎的答案和我的解决方案。我想有人会觉得这很有趣。干杯!

您可以使用Array.prototype.reduce()Array.prototype.concat()展平数组

var data = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"], ["$0"], ["$15"],["$3"], ["$75"], ["$5"], ["$100"], ["$7"], ["$3"], ["$75"], ["$5"]].reduce(function(a, b) {return a.concat(b);}, []);console.log(data);

相关文档:https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/concat

这里的大多数答案都不适用于大型(例如200,000个元素)数组,即使它们适用,它们也很慢。

这里是最快的解决方案,也适用于具有多个嵌套级别的数组

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

示例

巨大的阵列

flatten(Array(200000).fill([1]));

它可以很好地处理巨大的数组。在我的机器上,这段代码执行大约需要14毫秒。

嵌套数组

flatten(Array(2).fill(Array(2).fill(Array(2).fill([1]))));

它适用于嵌套数组。此代码产生[1, 1, 1, 1, 1, 1, 1, 1]

具有不同嵌套级别的数组

flatten([1, [1], [[1]]]);

对于像这样的扁平化数组,它没有任何问题。

请注意:当使用Function.prototype.apply[].concat.apply([], arrays))或扩展运算符([].concat(...arrays))来展平数组时,两者都可能导致大型数组的堆栈溢出,因为函数的每个参数都存储在堆栈上。

这是一个函数式的堆栈安全实现,它将最重要的需求相互权衡:

  • 可重用性
  • 易读性
  • 简洁
  • 性能

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

一旦你习惯了柯里化形式的小箭头函数、函数组合和高阶函数,这段代码读起来就像散文。编程仅仅是把总是按预期工作的小构建块放在一起,因为它们不包含任何副作用。

泛型过程意味着我们不必在每次需要利用特定行为时重写复杂性。

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 -> aconst id = x =>x
// flatten :: [[a]] -> [a]const flatten =concatMap (id)
// your sample dataconst data =[["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]
console.log (flatten (data))

远见

是的,你猜对了,它只是扁平化一个级别,这正是它应该的工作方式

想象一下这样的数据集

// Player :: (String, Number) -> Playerconst Player = (name,number) =>[ name, number ]
// team :: ( . Player) -> Teamconst Team = (...players) =>players
// Game :: (Team, Team) -> Gameconst Game = (teamA, teamB) =>[ teamA, teamB ]
// sample dataconst teamA =Team (Player ('bob', 5), Player ('alice', 6))
const teamB =Team (Player ('ricky', 4), Player ('julian', 2))
const game =Game (teamA, teamB)
console.log (game)// [ [ [ 'bob', 5 ], [ 'alice', 6 ] ],//   [ [ 'ricky', 4 ], [ 'julian', 2 ] ] ]

好的,现在假设我们要打印一个名册,显示所有将参加game的球员。

const gamePlayers = game =>flatten (game)
gamePlayers (game)// => [ [ 'bob', 5 ], [ 'alice', 6 ], [ 'ricky', 4 ], [ 'julian', 2 ] ]

如果我们的flatten过程也扁平化嵌套数组,我们最终会得到这个垃圾结果…

const gamePlayers = game =>badGenericFlatten(game)
gamePlayers (game)// => [ 'bob', 5, 'alice', 6, 'ricky', 4, 'julian', 2 ]

滚得很深,宝贝

这并不是说有时你也不想扁平化嵌套数组——只是这不应该是默认行为。

// 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 -> aconst id = x =>x
// flatten :: [[a]] -> [a]const flatten =concatMap (id)
// deepFlatten :: [[a]] -> [a]const deepFlatten =concatMap (x =>Array.isArray (x) ? deepFlatten (x) : x)
// your sample dataconst data =[0, [1, [2, [3, [4, 5], 6]]], [7, [8]], 9]
console.log (flatten (data))// [ 0, 1, [ 2, [ 3, [ 4, 5 ], 6 ] ], 7, [ 8 ], 9 ]
console.log (deepFlatten (data))// [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

好了,现在每个任务都有了一个工具——一个用于压缩一个级别的嵌套flatten,另一个用于消除所有嵌套deepFlatten

如果你不喜欢deepFlatten这个名字,也许你可以叫它obliteratenuke


不要重复两次!

当然,上面的实现是聪明和简洁的,但是使用.map然后调用.reduce意味着我们实际上做了比必要更多的迭代

使用我调用的可信赖的组合器mapReduce有助于将迭代保持在最小值;它需要一个映射函数m :: a -> b,一个缩减函数r :: (b,a) ->b并返回一个新的缩减函数-这个组合器是传感器的核心;如果你感兴趣,我写了其他关于他们的答案

// mapReduce = (a -> b, (b,a) -> b, (b,a) -> b)const mapReduce = (m,r) =>(acc,x) => r (acc, m (x))
// concatMap :: (a -> [b]) -> [a] -> [b]const concatMap = f => xs =>xs.reduce (mapReduce (f, concat), [])
// concat :: ([a],[a]) -> [a]const concat = (xs,ys) =>xs.concat (ys)
// id :: a -> aconst id = x =>x
// flatten :: [[a]] -> [a]const flatten =concatMap (id)  
// deepFlatten :: [[a]] -> [a]const deepFlatten =concatMap (x =>Array.isArray (x) ? deepFlatten (x) : x)
// your sample dataconst data =[ [ [ 1, 2 ],[ 3, 4 ] ],[ [ 5, 6 ],[ 7, 8 ] ] ]
console.log (flatten (data))// [ [ 1. 2 ], [ 3, 4 ], [ 5, 6 ], [ 7, 8 ] ]
console.log (deepFlatten (data))// [ 1, 2, 3, 4, 5, 6, 7, 8 ]

这是最好的解决方法

let flatten = arr => [].concat.apply([], arr.map(item => Array.isArray(item) ? flatten(item) : item))

我最初想使用.reduce方法并递归调用函数来展平内部数组,然而当你使用深度嵌套数组的深度嵌套数组时,这可能会导致堆栈溢出。使用concat也不是最好的方法,因为每次迭代都会创建数组的一个新的浅副本。我们可以做的是:

const flatten = arr => {for(let i = 0; i < arr.length;) {const val = arr[i];if(Array.isArray(val)) {arr.splice(i, 1, ...val);} else {i ++;}}return arr;}

我们不会通过concat创建新的数组,也不会递归调用任何函数。

http://jsbin.com/firiru/4/edit?js,控制台

我宁愿将整个数组按原样转换为字符串,但与其他答案不同,将使用JSON.stringify而不是使用toString()方法来执行此操作,这会产生不需要的结果。

使用JSON.stringify输出,剩下的就是删除所有括号,再次用开始和结束括号包装结果,并用JSON.parse提供结果,从而使字符串恢复“生命”。

  • 可以处理无限嵌套数组而无需任何速度成本。
  • 可以正确处理包含逗号的字符串的数组项。

var arr = ["abc",[[[6]]],["3,4"],"2"];
var s = "[" + JSON.stringify(arr).replace(/\[|]/g,'') +"]";var flattened = JSON.parse(s);
console.log(flattened)

  • 仅适用于字符串/数字的多维数组(不是对象)

我提出了两个没有递归的简短解决方案。从计算复杂性的角度来看,它们不是最佳的,但在平均情况下工作得很好:

let a = [1, [2, 3], [[4], 5, 6], 7, 8, [9, [[10]]]];
// Solution #1while (a.find(x => Array.isArray(x)))a = a.reduce((x, y) => x.concat(y), []);
// Solution #2let i = a.findIndex(x => Array.isArray(x));while (i > -1){a.splice(i, 1, ...a[i]);i = a.findIndex(x => Array.isArray(x));}

适用于所有数据类型的递归版本

 /*jshint esversion: 6 */
// nested array for testinglet nestedArray = ["firstlevel", 32, "alsofirst", ["secondlevel", 456,"thirdlevel", ["theinnerinner", 345, {firstName: "Donald", lastName: "Duck"}, "lastinner"]]];
// wrapper function to protect inner variable tempArray from global scope;function flattenArray(arr) {
let tempArray = [];
function flatten(arr) {arr.forEach(function(element) {Array.isArray(element) ? flatten(element) : tempArray.push(element);     // ternary check that calls flatten() again if element is an array, hereby making flatten() recursive.});}
// calling the inner flatten function, and then returning the temporary arrayflatten(arr);return tempArray;}
// example usage:let flatArray = flattenArray(nestedArray);
/*** flatten an array first level* @method flatten* @param array {Array}* @return {Array} flatten array*/function flatten(array) {return array.reduce((acc, current) => acc.concat(current), []);}

/*** flatten an array recursively* @method flattenDeep* @param array {Array}* @return {Array} flatten array*/function flattenDeep(array) {return array.reduce((acc, current) => {return Array.isArray(current) ? acc.concat(flattenDeep(current)) : acc.concat([current]);}, []);}
/*** flatten an array recursively limited by depth* @method flattenDepth* @param array {Array}* @return {Array} flatten array*/function flattenDepth(array, depth) {if (depth === 0) {return array;}return array.reduce((acc, current) => {return Array.isArray(current) ? acc.concat(flattenDepth(current, --depth)) : acc.concat([current]);}, []);}

这里的逻辑是将输入数组转换为字符串并删除所有括号([])并将输出解析为数组。我为此使用ES6模板功能。

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)

ES6方式:

const flatten = arr => arr.reduce((acc, next) => acc.concat(Array.isArray(next) ? flatten(next) : next), [])
const a = [1, [2, [3, [4, [5]]]]]console.log(flatten(a))

flatten函数的ES5方式,对于N次嵌套数组具有ES3回退:

var flatten = (function() {if (!!Array.prototype.reduce && !!Array.isArray) {return function(array) {return array.reduce(function(prev, next) {return prev.concat(Array.isArray(next) ? flatten(next) : next);}, []);};} else {return function(array) {var arr = [];var i = 0;var len = array.length;var target;
for (; i < len; i++) {target = array[i];arr = arr.concat((Object.prototype.toString.call(target) === '[object Array]') ? flatten(target) : target);}
return arr;};}}());
var a = [1, [2, [3, [4, [5]]]]];console.log(flatten(a));

const flatten = array => array.reduce((a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []);

根据要求,分解一行基本上是这样的。

function flatten(array) {// reduce traverses the array and we return the resultreturn 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 accumulatorreturn acc.concat( Array.isArray(b) ? flatten(b) : b);}, []); // we initialize the accumulator on an empty array to collect all the elements}

我推荐一个节省空间的发生器函数

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

如果需要,创建一个扁平化值数组,如下所示:

let flattened = [...flatten([1,[2,[3,[4]]]])]; // [1, 2, 3, 4]

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 to flatten deeply nested array]* @param  {[type]} arr          [The array to be flattened]* @param  {[type]} flattenedArr [The flattened array]* @return {[type]}              [The flattened array]*/function flattenDeepArray(arr, flattenedArr) {let length = arr.length;
for(let i = 0; i < length; i++) {if(Array.isArray(arr[i])) {flattenDeepArray(arr[i], flattenedArr);} else {flattenedArr.push(arr[i]);}}
return flattenedArr;}
let arr = [1, 2, [3, 4, 5], [6, 7]];
console.log(arr, '=>', flattenDeepArray(arr, [])); // [ 1, 2, [ 3, 4, 5 ], [ 6, 7 ] ] '=>' [ 1, 2, 3, 4, 5, 6, 7 ]
arr = [1, 2, [3, 4], [5, 6, [7, 8, [9, 10]]]];
console.log(arr, '=>', flattenDeepArray(arr, [])); // [ 1, 2, [ 3, 4 ], [ 5, 6, [ 7, 8, [Object] ] ] ] '=>' [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]

您可以继续使用Array.flat()方法来实现这一点,即使数组嵌套得多。

[1,2,3,[2]].flat()

相当于

[1,2,3,[2]].flat(1)

所以当你的嵌套增加时,你可以继续增加数量。

eg:

[1,[2,[3,[4]]]].flat(3) // [1, 2, 3, 4]

如果你不确定嵌套的级别,你可以将Infinity作为参数传递

[1,2,3,[2,[3,[3,[34],43],[34]]]].flat(Infinity) //[1, 2, 3, 2, 3, 3, 34, 43, 34]

您可以使用Ramda JS压平

var arr = [[1,2], [3], [4,5]];var flattenedArray = R.flatten(arr);
console.log(flattenedArray)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"></script>

有一个名为平面的新本机方法可以准确地执行此操作。

(截至2019年底,flat现已在ECMA 2019标准中发布,core-js@3(Babel的库)将其包含在他们的polyill库中

const arr1 = [1, 2, [3, 4]];arr1.flat();// [1, 2, 3, 4]
const arr2 = [1, 2, [3, 4, [5, 6]]];arr2.flat();// [1, 2, 3, 4, [5, 6]]
// Flatten 2 levels deepconst arr3 = [2, 2, 5, [5, [5, [6]], 7]];arr3.flat(2);// [2, 2, 5, 5, 5, [6], 7];
// Flatten all levelsconst arr4 = [2, 2, 5, [5, [5, [6]], 7]];arr4.flat(Infinity);// [2, 2, 5, 5, 5, 6, 7];
const common = arr.reduce((a, b) => [...a, ...b], [])

只是为了增加伟大的解决方案。我使用递归来解决这个问题。

            const flattenArray = () => {let result = [];return function flatten(arr) {for (let i = 0; i < arr.length; i++) {if (!Array.isArray(arr[i])) {result.push(arr[i]);} else {flatten(arr[i])}}return result;}}

测试结果:https://codepen.io/ashermike/pen/mKZrWK

let arr = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"], ["$0"], ["$15"],["$3"], ["$75"], ["$5"], ["$100"], ["$7"], ["$3"], ["$75"], ["$5"]];arr = arr.reduce((a, b) => a.concat(b)); // flattened

我用ES6回答这个问题,假设深度数组是:

const deepArray = ['1',[['a'],['b']],[2],[[[['4',[3,'c']]]],[5]]];

如果您知道或猜测数组的深度不超过7这样的数字,请使用以下代码:

const flatArray = deepArray.flat(7);

但是,如果您不知道深度数组的深度,或者您的JavaScript引擎不支持flat(如react-nativeJavaScriptCore),请使用下面的函数,该函数用于JavaScriptreduce函数:

 const deepFlatten = arr =>arr.reduce((acc, val) =>Array.isArray(val)? acc.concat(deepFlatten(val)): acc.concat(val),[]);

这两个方法都返回以下结果:

["1", "a", "b", 2, "4", 3, "c", 5]

我有一个简单的解决方案,无需在特殊的js函数中使用。(

const input = [[0, 1], [2, 3], [4, 5]]let flattened=[];
for (let i=0; i<input.length; ++i) {let current = input[i];for (let j=0; j<current.length; ++j)flattened.push(current[j]);}

更简单和直接的一个;选择深扁平化;

const flatReduce = (arr, deep) => {return arr.reduce((acc, cur) => {return acc.concat(Array.isArray(cur) && deep ? flatReduce(cur, deep) : cur);}, []);};
console.log(flatReduce([1, 2, [3], [4, [5]]], false)); // =>  1,2,3,4,[5]console.log(flatReduce([1, 2, [3], [4, [5, [6, 7, 8]]]], true)); // => 1,2,3,4,5,6,7,8

您可以将#0#1用于嵌套数组的任何深度。

var arr = [ [1,2,3,4], [1,2,[1,2,3]], [1,2,3,4,5,[1,2,3,4,[1,2,3,4]]], [[1,2,3,4], [1,2,[1,2,3]], [1,2,3,4,5,[1,2,3,4,[1,2,3,4]]]] ];
let flatten = arr.flat(Infinity)
console.log(flatten)

点击这里查看浏览器兼容性

最好在递归方式中执行,因此如果另一个数组中还有另一个数组,可以轻松地过滤

const flattenArray = arr =>arr.reduce((res, cur) =>!Array.isArray(cur)? res.concat(cur): res.concat(flattenArray(cur)), []);

你可以这样称呼它:

flattenArray([[["Alireza"], "Dezfoolian"], ["is a"], ["developer"], [[1, [2, 3], ["!"]]]);

结果如下:

["Alireza", "Dezfoolian", "is a", "developer", 1, 2, 3, "!"]

这是一个基于artif3x答案的TypeScript版本,为Scala粉丝提供了flatMap的奖励实现。

function flatten<T>(items: T[][]): T[] {return items.reduce((prev, next) => prev.concat(next), []);}
function flatMap<T, U>(items: T[], f: (t: T) => U[]): U[] {return items.reduce((prev, next) => prev.concat(f(next)), new Array<U>());}

平坦阵列的制作方法

  • 使用Es6平面()
  • 使用Es6 Reduce()
  • 使用递归
  • 使用字符串操作

[1,[2,[3,[4,[5,[6,7],8],9],10]]] - [1,2,3,4,5,6,7,8,9,10]

// using Es6 flat()let arr = [1,[2,[3,[4,[5,[6,7],8],9],10]]]console.log(arr.flat(Infinity))
// using Es6 reduce()let flatIt = (array) => array.reduce((x, y) => x.concat(Array.isArray(y) ? flatIt(y) : y), [])console.log(flatIt(arr))
// using recursionfunction myFlat(array) {let flat = [].concat(...array);return flat.some(Array.isArray) ? myFlat(flat) : flat;}console.log(myFlat(arr));
// using string manipulationlet strArr = arr.toString().split(',');for(let i=0;i<strArr.length;i++)strArr[i]=parseInt(strArr[i]);
console.log(strArr)

纯粹的魔法ES6

const flat = A => A.reduce((A, a) => Array.isArray(a) ? [...A, ...flat(a)] : [...A, a], []);

如果你用的是土豆泥,你可以用它的flatten方法:https://lodash.com/docs/4.17.14#flatten

Lodash的好处是它也有扁平化数组的方法:

递归:https://lodash.com/docs/4.17.14#flattenDeep

ii)多达n个嵌套级别:https://lodash.com/docs/4.17.14#flattenDepth

例如

const _ = require("lodash");const pancake =  _.flatten(array)

简单的扁平化直到我写

const flatten = (arr, result = []) => {if (!Array.isArray(arr)){return [...result, arr];}arr.forEach((a) => {result = flatten(a, result)})
return result}
console.log(flatten([1,[2,3], [4,[5,6,[7,8]]]])) // [ 1, 2, 3, 4, 5, 6, 7, 8 ]

在javascript中定义一个名为foo的数组数组,并使用javascript的数组concat内置方法将该数组展平为单个数组:

const foo = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]console.log({foo});
const bar = [].concat(...foo)console.log({bar});

应该打印:

{ foo:[ [ '$6' ],[ '$12' ],[ '$25' ],[ '$25' ],[ '$18' ],[ '$22' ],[ '$10' ] ] }{ bar: [ '$6', '$12', '$25', '$25', '$18', '$22', '$10' ] }

由于ES2019引入了平面和平面映射,因此任何数组都可以这样做:

const myArr = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]const myArrFlat= myArr.flat(Infinity);console.log(myArrFlat); // ["$6", "$12", "$25", ...]

递归调用deepFlatten函数,这样我们就可以在不使用任何外部辅助方法的情况下扩展内部数组。

const innerArr = ['a', 'b'];const multiDimArr = [[1, 2], 3, 4, [5, 6, innerArr], 9];
const deepFlatten = (arr) => {const flatList = [];arr.forEach(item => {Array.isArray(item)? flatList.push(...deepFlatten(item)) // recursive call: flatList.push(item)});return flatList;}

此解决方案适用于数组的任何深度级别(指定嵌套数组结构的深度)。

function flatten(obj) {var out = [];function cleanElements(input) {for (var i  in input){if (input[i]instanceof Array){cleanElements(input[i]);}else {out.push(input[i]);}}}cleanElements(obj);return (out);}

您也可以尝试新的#0方法。它以以下方式工作:

let arr = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]].flat()
console.log(arr);

flat()方法创建一个新数组,其中所有子数组元素递归连接到1层深度(即数组内的数组)

如果您还想展平3维甚至更高维的数组,您只需多次调用平面方法。例如(3维):

let arr = [1,2,[3,4,[5,6]]].flat().flat().flat();
console.log(arr);

小心!

#0方法相对较新。像ie这样的旧浏览器可能没有实现该方法。如果您希望您的代码在所有浏览器上运行,您可能必须将您的JS转换为旧版本。检查MDN web文档以了解当前浏览器的兼容性。

我认为array.flat(Infinity)是一个完美的解决方案。但是平面函数是一个相对较新的函数,可能无法在旧版本的浏览器中运行。我们可以使用递归函数来解决这个问题。

const arr = ["A", ["B", [["B11", "B12", ["B131", "B132"]], "B2"]], "C", ["D", "E", "F", ["G", "H", "I"]]]const flatArray = (arr) => {const res = []for (const item of arr) {if (Array.isArray(item)) {const subRes = flatArray(item)res.push(...subRes)} else {res.push(item)}}
return res}
console.log(flatArray(arr))

使用传播运算符:

const input = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]];const output = [].concat(...input);console.log(output); // --> ["$6", "$12", "$25", "$25", "$18", "$22", "$10"]

这是递归方法…

function flatten(arr){let newArray = [];for(let i=0; i< arr.length; i++){if(Array.isArray(arr[i])){newArray =  newArray.concat(flatten(arr[i]))}else{newArray.push(arr[i])}}return newArray;}
console.log(flatten([1, 2, 3, [4, 5] ])); // [1, 2, 3, 4, 5]console.log(flatten([[[[1], [[[2]]], [[[[[[[3]]]]]]]]]]))  // [1,2,3]console.log(flatten([[1],[2],[3]])) // [1,2,3]

另一种使用jQuery$. map()函数的方法。jQuery留档:

该函数可以返回一个值数组,该数组将被展平为完整数组。

var source = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]];var target = $.map(source, function(value) { return value; }); // ["$6", "$12", "$25", "$25", "$18", "$22", "$10"]

使用此方法平坦两个数组

arr1.concat(...arr2);
function flatten(input) {let result = [];  
function extractArrayElements(input) {for(let i = 0; i < input.length; i++){if(Array.isArray(input[i])){extractArrayElements(input[i]);}else{result.push(input[i]);}}}  
extractArrayElements(input);  
return result;}

// let input = [1,2,3,[4,5,[44,7,8,9]]];// console.log(flatten(input));
// output [1,2,3,4,5,6,7,8,9]

这是打字稿中最快的解决方案,它也适用于具有多个嵌套级别的数组:

export function flatten<T>(input: Array<any>, output: Array<T> = []): Array<T> {for (const value of input) {Array.isArray(value) ? flatten(value, output) : output.push(value);}return output;}

而不是:

const result = flatten<MyModel>(await Promise.all(promises));

简单地使用扩展运算符,我们可以通过以下方式展平。

var OriginalArray = [[5, 1], [6], [2], [8]];var newArray = [];
for (let i = 0; i < OriginalArray.length; i++) {newArray.push(...OriginalArray[i]);}
console.log(newArray)

我刚刚尝试在不使用任何内置函数的情况下解决问题。

var arr = [1, 3, 4, 65, [3, 5, 6, 9, [354, 5, 43, 54, 54, 6, [232, 323, 323]]]];var result = [];
function getSingleArray(inArr) {for (var i = 0; i < inArr.length; i++) {if (typeof inArr[i] == "object") {getSingleArray(inArr[i]); // Calling Recursively} else {result.push(inArr[i]);}}}
getSingleArray(arr);console.log(result); // [1, 3, 4, 65, 3, 5, 6, 9, 354, 5, 43, 54, 54, 6, 232, 323, 323]

这是使用堆栈的非递归展平深度的解决方案。

    function flatten(input) {const stack = [...input];const res = [];while (stack.length) {const next = stack.pop();if (Array.isArray(next)) {stack.push(...next);} else {res.push(next);}}return res.reverse();}const arrays = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]];flatten(arrays);
const arr = [1, 2, [3, 4]];
arr.reduce((acc, val) => acc.concat(val), []);

如果您的编码环境支持ES6(ES2015),则无需编写任何递归函数或使用map、duce等数组方法。

一个简单的点差算子(…)将帮助您将数组的数组展平为单个数组

eg:

  const data = [[1, 2, 3], [4, 5],[2]]let res = []data.forEach(curSet=>{res = [...res,...curSet]})console.log(res) //[1, 2, 3, 4, 5, 2]

您可以使用"join()"//拆分//拆分

let arrs = [["$6"],["$12"],["$25"],["$25"],["$18"],["$22"],["$10"]];
let newArr = arrs.join(",").split(",");
console.log(newArr); // ["$6", "$12", "$25", "$25", "$18", "$22", "$10"]

此外,您还可以使用"toString()"接口说明//拆分//拆分

let arrs = [["$6"],["$12"],["$25"],["$25"],["$18"],["$22"],["$10"]];
let newArr = arrs.toString().split(",");
console.log(newArr); // ["$6", "$12", "$25", "$25", "$18", "$22", "$10"]

但是,如果字符串包含逗号,上述两种方式都无法正常工作

"join()"//拆分//拆分

let arrs = [["$,6"],["$,12"],["$2,5"],["$2,5"],[",$18"],["$22,"],["$,1,0"]];
let newArr = arrs.join(",").split(",");
console.log(newArr);// ["$", "6", "$", "12", "$2", "5", "$2", "5", "", "$18", "$22", "", "$", "1", "0"]

let arrs = [["$,6"],["$,12"],["$2,5"],["$2,5"],[",$18"],["$22,"],["$,1,0"]];
let newArr = arrs.toString().split(",");
console.log(newArr);// ["$", "6", "$", "12", "$2", "5", "$2", "5", "", "$18", "$22", "", "$", "1", "0"]

let arr = [1, [2, 3, [4, 5, [6, 7], [8, 9, 10, 11, 12]]]];
function flattenList(nestedArr) {let newFlattenList = [];
const handleFlat = (array) => {let count = 0;while (count < array.length) {let item = array[count];if (Array.isArray(item)) {handleFlat(item);} else {newFlattenList.push(item);}count++;}};handleFlat(nestedArr);return newFlattenList;}`enter code here`
console.log(flattenList(arr));

function flattenArray(deepArray) {// check if Arrayif(!Array.isArray(deepArray)) throw new Error('Given data is not an Array')
const flatArray = deepArray.flat() // flatten arrayconst filteredArray = flatArray.filter(item => !!item) // filter by Booleanconst uniqueArray = new Set(filteredArray) // filter by unique values    
return [...uniqueArray] // convert Set into Array}

const flattenArray = (deepArray) => [...new Set(deepArray.flat().filter(item=>!!item))]
flattenArray([4,'a', 'b', [3, 2, undefined, 1], [1, 4, null, 5]])) // 4,'a','b',3,2,1,5

Codesandbox link

现代方法

使用[].平(无穷大)方法

const nestedArray = [1,[2,[3],[4,[5,[6,[7]]]]]]const flatArray = nestedArray.flat(Infinity)console.log(flatArray)

以下是如何将任何深度的嵌套数组展平。

const arr = [32,3,2,[323,[3223],[3,6,[8]]]];console.log(arr.flat(Infinity));

我假设您已经知道平面方法带有深度参数,您可以为其分配任何深度。


例如arr.flat(2);/*这将使数组展平到深度2*/