在JavaScript中合并/展平数组数组?

And*_*ndy 1001 javascript arrays flatten

我有一个JavaScript数组,如:

[["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]
Run Code Online (Sandbox Code Playgroud)

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

["$6", "$12", "$25", ...]
Run Code Online (Sandbox Code Playgroud)

Gum*_*mbo 1713

您可以使用concat合并数组:

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

console.log(merged);
Run Code Online (Sandbox Code Playgroud)

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

var merged2 = [].concat(["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]);
Run Code Online (Sandbox Code Playgroud)

还有一种实验Array.prototype.flat()方法(尚未成为ECMAScript标准的一部分),您可以使用它来展平阵列,尽管它在Edge或Node.js中尚不可用.

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);
    
Run Code Online (Sandbox Code Playgroud)

  • 继@ Sean的评论:ES6语法使这个超级简洁:`var merged = [] .concat(... arrays)` (185认同)
  • `var merged = [] .concat.apply([],arrays);`似乎可以正常工作,将它放在一行上.编辑:尼基塔的答案已经显示. (63认同)
  • 或者`Array.prototype.concat.apply([],arrays)`. (44认同)
  • 注意:这个答案只会在一个层面上变平.对于递归展平,请参阅@Trindaz的答案. (29认同)
  • 注意`concat`不会修改源数组,所以`merged`数组在调用`concat`后将保持为空.更好地说:`merged = merged.concat.apply(merged,arrays);` (10认同)
  • 基于@Sethi 的评论:`Array.prototype.concat(...arrays)`。此版本适用于 Typescript 2.3.0 `--strict` 模式。不适用于嵌套数组(它不是递归的)。 (2认同)
  • 对于某些虚拟机(例如v8),“ apply”将在大型输入上堆栈溢出。确实不是这个用例的意思。 (2认同)
  • 正如 @Sethi 提到的,对于 ES6:`[].concat(...arrays)` 也适用于 Typescript (2认同)
  • Array.prototype.flat 现已正式发布!并且[在 Chrome、Firefox、Opera、Safari 中受支持](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat)! (2认同)
  • 出于好奇,为什么在 `var merged = [].concat.apply([], arrays);` 中, thisArg 设置为空数组? (2认同)

Noa*_*tas 466

这是一个简短的函数,它使用一些较新的JavaScript数组方法来展平n维数组.

function flatten(arr) {
  return arr.reduce(function (flat, toFlatten) {
    return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
  }, []);
}
Run Code Online (Sandbox Code Playgroud)

用法:

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]
Run Code Online (Sandbox Code Playgroud)

  • 或者是一种更短,更性感的形式:`const flatten =(arr)=> arr.reduce((flat,next)=> flat.concat(next),[]);` (18认同)
  • 我喜欢这种方法.它更通用,支持嵌套数组 (16认同)
  • 重复@TsvetomirTsonev和Noah的任意嵌套解决方案:`const flatten =(arr)=> arr.reduce((flat,next)=> flat.concat(Array.isArray(next)?flatten(next):next), []);` (11认同)
  • 此解决方案的内存使用情况如何?看起来它在尾递归期间创建了很多中间数组.... (9认同)
  • @ayjay,它是reduce函数的起始累加器值,[mdn](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce)调用初始值.在这种情况下,它是第一次调用传递给`reduce`的匿名函数时`flat`的值.如果未指定,则第一次调用`reduce`将数组中的第一个值绑定到`flat`,这最终会导致`1`在两个示例中都绑定到`flat`.`1.concat`不是一个函数. (6认同)
  • 为什么会有一个空数组作为参数传递?没有它,代码就会中断,但是它会做什么呢? (2认同)
  • @GeorgeKatsanos 我们不知道 - 是的,`concat` 应该创建一个新数组,但是运行时可以像嘿已经做的那样优化,例如针对多种字符串操作。如果他们检测到数组立即被丢弃,他们甚至可以专门将检测限制在 `reduce` 函数中,他们可以在内部重用相同的数组。对于你的采访,我会说任何认为 JS 代码的可观察行为总是与运行时内部所做的完全相同的人不应该被拒绝,但绝对应该受到教育——这些东西可能随时改变。 (2认同)

Nik*_*kov 305

这是一个简单而高效的功能解决方案:

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

没有必要的混乱.

  • @paldepind 1.在进行无意义指控之前,你应该至少熟悉函数式编程的定义.我的代码不会改变值,这就是它的功能.期.2. JS的本机函数由VM执行,在大多数情况下,它提供了在C中完成的优化实现,而不是在库中.即使我的代码使用了强制实现的库,它本身仍然可以实现.4.任何语言编译为机器代码,这都是关于改变存储器单元的,所以根据你的定义,每种语言都是必不可少的,这简直荒谬. (24认同)
  • 我想我也发现了你的错误.`...`是实际代码,而不是一些省略号点. (21认同)
  • 在CoffeeScript中,这是`[] .concat([[1],[2,3],[4]] ...)` (11认同)
  • @amoebe你的答案给出了[[[1],[2,3],[4]]`的结果.@Nikita给出的解决方案对于CoffeeScript和JS都是正确的. (8认同)
  • 啊,我发现了你的错误.你的符号中有一对额外的方括号,应该是`[] .concat([1],[2,3],[4],...)`. (5认同)
  • 使用库函数并不意味着任何不那么紧迫的"混乱".只是把乱七八糟的东西隐藏在图书馆里面.显然使用库比滚动自己的函数更好,但声称这种技术减少"命令性混乱"是非常愚蠢的. (3认同)
  • @paldepind建议的方法不使用任何库,而是标准的JS函数.它不会改变任何值,这就是为什么它不是必要的,而是功能性的.所以我不明白你究竟发现了什么. (3认同)
  • @ lama12345据我所知,这不起作用.我能做的最接近的是`Array.prototype.concat.apply([],[[1],[2,3],[4]])` (3认同)
  • 如果您可以使用ES2015,您也可以使用数组传播更容易地编写它:`[] .concat(... [[1],[2,3],[4]])`. (2认同)
  • 不适用于数组[2,[3,[4,[5,[6,[7,[8]]]]]]] (2认同)

小智 183

最好通过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);
}, []);
Run Code Online (Sandbox Code Playgroud)

或者,使用ES2015:

arrays = arrays.reduce((a, b) => a.concat(b), []);
Run Code Online (Sandbox Code Playgroud)

JS-小提琴

Mozilla文档

  • 由于您使用ES6,您还可以使用[spread-operator as array literal](https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Operators/Spread_operator).`arrays.reduce((flatten,arr)=> [... flatten,... arr])` (6认同)
  • @calbertts只传递初始值`[]`,不需要进一步的验证. (4认同)
  • 我也会使用reduce,但是我从这个片段中学到的一个有趣的事情是**大多数时候你不需要传递一个initialValue**:) (3认同)
  • reduce的问题在于数组不能为空,因此您需要添加一个额外的验证。 (2认同)

Mic*_*ski 71

这里的大多数答案不适用于巨大的(例如200 000个元素)阵列,即使它们这样做,它们也很慢.polkovnikov.ph的答案具有最佳性能,但它不适用于深度扁平化.

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

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;
};
Run Code Online (Sandbox Code Playgroud)

例子

巨大的阵列

flatten(Array(200000).fill([1]));
Run Code Online (Sandbox Code Playgroud)

它处理大型数组就好了.在我的机器上,此代码执行大约需要14毫秒.

嵌套数组

flatten(Array(2).fill(Array(2).fill(Array(2).fill([1]))));
Run Code Online (Sandbox Code Playgroud)

它适用于嵌套数组.这段代码产生了[1, 1, 1, 1, 1, 1, 1, 1].

具有不同嵌套级别的数组

flatten([1, [1], [[1]]]);
Run Code Online (Sandbox Code Playgroud)

像这样的扁平化数组没有任何问题.

  • 通常,当用户生成的内容生成数组时. (2认同)
  • O符号的复杂度是多少? (2认同)

Ali*_*ter 64

有一个名为flat的新的原生ECMA 2018方法可以完全做到这一点.

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 deep
const arr3 = [2, 2, 5, [5, [5, [6]], 7]];
arr3.flat(2);
// [2, 2, 5, 5, 5, [6], 7];

// Flatten all levels
const arr4 = [2, 2, 5, [5, [5, [6]], 7]];
arr4.flat(Infinity);
// [2, 2, 5, 5, 5, 6, 7];
Run Code Online (Sandbox Code Playgroud)

  • 我想现在我们可以考虑这个..因为现在它是标准(2019)的一部分..我们可以重新审视一下性能部分吗? (4认同)
  • 令人遗憾的是,这甚至不是第一页的答案.此功能适用于Chrome 69和Firefox 62(以及适用于后端工作人员的Node 11) (3认同)
  • -1; 不,这不是[ECMAScript 2018](http://www.ecma-international.org/ecma-262/9.0/)的一部分。它仍然只是一个提案,尚未纳入任何ECMAScript规范。 (2认同)

Mic*_*ski 54

更新:事实证明,此解决方案不适用于大型阵列.您正在寻找更好,更快的解决方案,请查看此答案.


function flatten(arr) {
  return [].concat(...arr)
}
Run Code Online (Sandbox Code Playgroud)

只是扩展arr并将其作为参数传递给它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
    )
  )
}
Run Code Online (Sandbox Code Playgroud)

请参阅JSBin上的演示.

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


附注:find()所有浏览器都不支持类似和箭头功能的方法,但这并不意味着您现在无法使用这些功能.只需使用Babel - 它将ES6代码转换为ES5.

  • @GEMI例如,尝试使用此方法展平500000元素数组会出现"RangeError:超出最大调用堆栈大小". (3认同)

Tod*_*ell 50

你可以使用下划线:

var x = [[1], [2], [3, 4]];

_.flatten(x); // => [1, 2, 3, 4]
Run Code Online (Sandbox Code Playgroud)

  • 哇,有人在JS中添加了Perl吗?:-) (20认同)
  • @JBRWilkinson也许JS想要为大家学习Haskell!? (9认同)
  • 关于@ styfle评论的完整性:http://learnyouahaskell.com/ (7认同)

Tha*_*you 41

通用程序意味着每次我们需要利用特定行为时,我们不必重写复杂性.

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))
Run Code Online (Sandbox Code Playgroud)

先见之明

是的,你猜对了,它只会使一个级别变平,这正是它应该如何运作的

想象一下像这样的一些数据集

// Player :: (String, Number) -> Player
const Player = (name,number) =>
  [ name, number ]

// team :: ( . Player) -> Team
const Team = (...players) =>
  players

// Game :: (Team, Team) -> Game
const Game = (teamA, teamB) =>
  [ teamA, teamB ]

// sample data
const 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 ] ] ]
Run Code Online (Sandbox Code Playgroud)

好的,现在说我们要打印一个名单,显示所有参与的球员game......

const gamePlayers = game =>
  flatten (game)

gamePlayers (game)
// => [ [ 'bob', 5 ], [ 'alice', 6 ], [ 'ricky', 4 ], [ 'julian', 2 ] ]
Run Code Online (Sandbox Code Playgroud)

如果我们的flatten程序也使嵌套数组变平,我们最终会得到这个垃圾结果......

const gamePlayers = game =>
  badGenericFlatten(game)

gamePlayers (game)
// => [ 'bob', 5, 'alice', 6, 'ricky', 4, 'julian', 2 ]
Run Code Online (Sandbox Code Playgroud)

罗林'深,宝贝

这并不是说有时候你也不想整理嵌套数组 - 只是不应该是默认行为.

我们可以轻松制作deepFlatten程序......

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

// deepFlatten :: [[a]] -> [a]
const deepFlatten =
  concatMap (x =>
    Array.isArray (x) ? deepFlatten (x) : x)

// your sample data
const 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 ]
Run Code Online (Sandbox Code Playgroud)

那里.现在,每个作业都有一个工具 - 一个用于压缩一个嵌套级别flatten,另一个用于清除所有嵌套deepFlatten.

也许你可以打电话obliterate或者nuke你不喜欢这个名字deepFlatten.


不要迭代两次!

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

使用可信赖的组合器,我正在调用mapReduce有助于将迭代保持为minium; 它需要一个映射功能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 -> a
const 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 data
const 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 ]
Run Code Online (Sandbox Code Playgroud)


Tri*_*daz 32

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

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;
}
Run Code Online (Sandbox Code Playgroud)

  • 这种方法在展平您从[JsonPath查询](https://code.google.com/p/jsonpath/wiki/Javascript)获得的结果集的嵌套数组形式时非常有效. (4认同)
  • 这个答案不完整!递归的结果从未在任何地方分配,因此递归的结果将丢失 (2认同)
  • @r3wt 继续并添加了一个修复程序。您需要做的是确保您正在维护的当前数组 `r` 将实际连接递归的结果。 (2认同)

diz*_*iaq 29

功能风格的另一个ECMAScript 6解决方案:

声明功能:

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

并使用它:

flatten( [1, [2,3], [4,[5,[6]]]] ) // -> [1,2,3,4,5,6]
Run Code Online (Sandbox Code Playgroud)

更新:

还要考虑现代浏览器的最新版本中提供的本机函数Array.prototype.flat()(ES6的提议).

感谢@(КонстантинВан)和@(Mark Amery)在评论中提及它.

  • 这很好而且整洁,但我认为你做了ES6过量.外部函数不需要是箭头函数.我会坚持使用箭头函数来减少回调但是变平自己应该是​​一个正常的函数. (3认同)
  • @StephenSimpson但外部函数是否需要*非*-arrow函数?*"扁平化本身应该是正常的功能"* - "正常"你的意思是"非箭头",但为什么呢?*为什么*在呼叫中使用箭头功能减少呢?你能提供你的推理线吗? (3认同)

rab*_*rab 27

怎么用的reduce(callback[, initialValue])方法JavaScript 1.8

list.reduce((p,n) => p.concat(n),[]);
Run Code Online (Sandbox Code Playgroud)

会做的工作.

  • `[[1],[2,3]].reduce((a,b)=> a.concat(b),[])`更性感. (8认同)
  • 在我们的例子中不需要第二个参数简单的`[[1],[2,3]].reduce((a,b)=> a.concat(b))` (5认同)

Den*_*ret 25

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

for (var i = 0; i < a.length; i++) {
  a[i] = a[i][0];
}
Run Code Online (Sandbox Code Playgroud)

对于downvoters:请阅读问题,不要downvote,因为它不适合你非常不同的问题.对于问题,这个解决方案既是最快也最简单的.

  • @dystroy for循环的条件部分不可读.或者只是我:D (9认同)
  • 我会说,"不要寻找更神秘的东西." ^^ (4认同)
  • 我的意思是......当我看到人们建议使用图书馆时......那太疯狂了...... (4认同)
  • 它有多么神秘并不重要.这段代码将"['foo',['bar']]`"扁平化为"['f','bar']`. (4认同)
  • 啊,使用图书馆*只是为了这个将是愚蠢的...但如果它已经可用. (3认同)
  • (我不确定`map`,`flatMap`或`flatten`函数如何使它的可读性降低或实际上更慢.但这个解决方案的+1会让我想到C.) (2认同)
  • "神秘"......说真的......即使是最年轻的"程序员"也不应该发现"神秘"的反向循环. (2认同)
  • 好.当然.这是问题的答案.*数组*中有什么不清楚?这个答案并没有试图回答一个效率较低的更普遍的问题...... (2认同)

Wil*_*een 22

您也可以尝试新Array.flat()方法。它以下列方式工作:

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

console.log(arr);
Run Code Online (Sandbox Code Playgroud)

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

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

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

console.log(arr);
Run Code Online (Sandbox Code Playgroud)

当心!

Array.flat()方法比较新。像 ie 这样的旧浏览器可能没有实现该方法。如果你想让你的代码在所有浏览器上工作,你可能必须将你的 JS 转换成旧版本。检查MDN 网络文档以了解当前浏览器的兼容性。

  • 要平坦更高维的数组,您只需使用“Infinity”参数调用平坦方法即可。像这样:`arr.flat(Infinity)` (2认同)

Yai*_*wil 20

const common = arr.reduce((a, b) => [...a, ...b], [])
Run Code Online (Sandbox Code Playgroud)


小智 14

请注意:当使用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));
Run Code Online (Sandbox Code Playgroud)

一旦习惯了咖喱形式,函数组合和高阶函数的小箭头函数,这段代码就像散文一样.编程然后仅仅包括总是按预期工作的小构建块,因为它们不包含任何副作用.

  • @Daerdemandt但是如果你把它写成单独的函数,你可能会在其他代码中重用它们. (3认同)
  • 如果您发现自己在语言B中实现了语言A的功能而不是作为项目的一部分,其唯一目标就是完成此操作,那么某个地方的某个人已经走错了路.可能是你吗?只需要使用`const flatten =(arr)=> arr.reduce((a,b)=> a.concat(b),[]);`为你的队友保存视觉垃圾*和*解释为什么你需要3额外的功能*和*一些函数调用. (2认同)

Cat*_*ish 11

使用扩展运算符:

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


zur*_*fyx 10

ES6 One Line Flatten

lodash flatten,undercore flatten (浅true)

function flatten(arr) {
  return arr.reduce((acc, e) => acc.concat(e), []);
}
Run Code Online (Sandbox Code Playgroud)

要么

function flatten(arr) {
  return [].concat.apply([], arr);
}
Run Code Online (Sandbox Code Playgroud)

经过测试

test('already flatted', () => {
  expect(flatten([1, 2, 3, 4, 5])).toEqual([1, 2, 3, 4, 5]);
});

test('flats first level', () => {
  expect(flatten([1, [2, [3, [4]], 5]])).toEqual([1, 2, [3, [4]], 5]);
});
Run Code Online (Sandbox Code Playgroud)

ES6 One Line Deep Flatten

lodash flattenDeep,下划线

function flattenDeep(arr) {
  return arr.reduce((acc, e) => Array.isArray(e) ? acc.concat(flattenDeep(e)) : acc.concat(e), []);
}
Run Code Online (Sandbox Code Playgroud)

经过测试

test('already flatted', () => {
  expect(flattenDeep([1, 2, 3, 4, 5])).toEqual([1, 2, 3, 4, 5]);
});

test('flats', () => {
  expect(flattenDeep([1, [2, [3, [4]], 5]])).toEqual([1, 2, 3, 4, 5]);
});
Run Code Online (Sandbox Code Playgroud)


Cod*_*iac 9

您可以将Array.flat()with Infinity用于任何深度的嵌套数组。

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)
Run Code Online (Sandbox Code Playgroud)

在此处查看浏览器兼容性


Art*_*ysh 8

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))
Run Code Online (Sandbox Code Playgroud)

ES5方式用于flattenN次嵌套数组的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));
Run Code Online (Sandbox Code Playgroud)


Red*_*edu 8

一种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);
Run Code Online (Sandbox Code Playgroud)

  • 为什么这个答案没有更多投票?! (2认同)

tld*_*ldr 8

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

lodash 的好处是它还有压平数组的方法:

i)递归地: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)
Run Code Online (Sandbox Code Playgroud)


Flo*_*vic 7

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

[["$6"], ["$12"], ["$25"], ["$25"]].join(',').split(',');
Run Code Online (Sandbox Code Playgroud)

会做的.Bt特别匹配您的代码示例.

  • 无论谁投票,请解释原因.我正在寻找一个体面的解决方案以及我最喜欢的所有解决方案. (3认同)
  • @Anonymous我没有投票,因为它在技术上满足了问题的要求,但可能是因为这是一个非常糟糕的解决方案,在一般情况下无用.考虑到这里有多少更好的解决方案,我永远不会建议有人选择这个,因为它打破了你有多个元素的时刻,或者当它们不是字符串时. (2认同)
  • 我喜欢这个解决方案=) (2认同)
  • 它不处理只是用1个字符串元素阵列,它也能处理这个数组`[ '$ 4',[ "$ 6"],[ "$ 12"],[ "$ 25"],[ "$ 25", "$ 33", [ '$ 45']]].加入( ' ').分裂(',')` (2认同)

Vas*_*kov 7

var arrays = [["a"], ["b", "c"]];
Array.prototype.concat.apply([], arrays);

// gives ["a", "b", "c"]
Run Code Online (Sandbox Code Playgroud)

(我只是根据@danhbear的评论将其作为一个单独的答案.)


le_*_*e_m 7

我推荐一个节省空间的发电机功能:

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
Run Code Online (Sandbox Code Playgroud)

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

let flattened = [...flatten([1,[2,[3,[4]]]])]; // [1, 2, 3, 4]
Run Code Online (Sandbox Code Playgroud)


vsy*_*ync 6

我宁愿将整个数组按原样转换为字符串,但与其他答案不同,它会使用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)
Run Code Online (Sandbox Code Playgroud)

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


Yaz*_*jar 6

有 2 种方法可以让您的阵列变平

* 1-第一个你可以使用 Array.prototype.flat 方法

const veryDeep = [[1, [2, 2, [3, [4, [5, [6]]]]], 1]];

veryDeep.flat(Infinity)
 // [1, 2, 2, 3, 4, 5, 6, 1]
 /**  If you don't know the depth of the array, 
simply pass Infinity **\
Run Code Online (Sandbox Code Playgroud)

或者,如果您知道数组嵌套了多少,则可以输入参数

const twoLevelsDeep = [[1, [2, 2], 1]];
//depth = 1
twoLevelsDeep.flat();
[1, [2, 2], 1]

//depth = 2
twoLevelsDeep.flat(2);
// [1, 2, 2, 1]
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

* 2-Second 方法你可以通过在 ES6 中使用扩展运算符来展平你的数组,并且 Concat 它将展平你的数组,不管它有多少嵌套

 const multidimension = [, [, , ], , [, ]];

   [].concat(...multidimension); // This will return: [, , , , , , 
   ]

   const multidimension = [1, [2, 3, 4], 5, [6, 7]];

   [].concat(...multidimension); // This will return: [1, 2, 3, 4, 5, 6, 7]
Run Code Online (Sandbox Code Playgroud)


Nik*_*iko 5

这并不难,只需遍历数组并合并它们:

var result = [], input = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"]];

for (var i = 0; i < input.length; ++i) {
    result = result.concat(input[i]);
}
Run Code Online (Sandbox Code Playgroud)


Jai*_*Jai 5

看起来这看起来像是RECURSION的工作!

  • 处理多层嵌套
  • 处理空数组和非数组参数
  • 没有变异
  • 不依赖于现代浏览器功能

码:

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);
  }
};
Run Code Online (Sandbox Code Playgroud)

用法:

flatten([1,[2,3],4,[[5,6],7]]);
// Result: [1, 2, 3, 4, 5, 6, 7] 
Run Code Online (Sandbox Code Playgroud)


小智 5

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

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;
}
Run Code Online (Sandbox Code Playgroud)


ash*_*ell 5

前几天我和ES6 Generators一起,并写下了这个要点.其中包含...

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);
Run Code Online (Sandbox Code Playgroud)

基本上我正在创建一个循环在原始输入数组上的生成器,如果它找到一个数组,它会使用yield*运算符和递归来连续展平内部数组.如果该项不是数组,则只生成单个项.然后使用ES6 Spread运算符(又名splat运算符),我将生成器展平为一个新的数组实例.

我没有测试过它的性能,但我认为它是使用生成器和yield*运算符的一个很好的简单例子.

但同样,我只是在玩弄,所以我确信有更多高效的方法可以做到这一点.


Vla*_*nov 5

只是没有lodash的最佳解决方案

let flatten = arr => [].concat.apply([], arr.map(item => Array.isArray(item) ? flatten(item) : item))
Run Code Online (Sandbox Code Playgroud)


akh*_*hid 5

扁平化数组的制作方法

  • 使用 Es6 flat()
  • 使用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 recursion
function myFlat(array) {
  let flat = [].concat(...array);
  return flat.some(Array.isArray) ? myFlat(flat) : flat;
}
console.log(myFlat(arr));

// using string manipulation
let strArr = arr.toString().split(','); 
for(let i=0;i<strArr.length;i++)
  strArr[i]=parseInt(strArr[i]);

console.log(strArr)
Run Code Online (Sandbox Code Playgroud)

  • 哪个最快? (2认同)

Top*_*pW3 5

我认为 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))
Run Code Online (Sandbox Code Playgroud)


小智 5

这是递归方式...

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]
Run Code Online (Sandbox Code Playgroud)


小智 5

您可以使用“join()”“split()”

let arrs = [
  ["$6"],
  ["$12"],
  ["$25"],
  ["$25"],
  ["$18"],
  ["$22"],
  ["$10"]
];

let newArr = arrs.join(",").split(",");

console.log(newArr); // ["$6", "$12", "$25", "$25", "$18", "$22", "$10"]
Run Code Online (Sandbox Code Playgroud)

此外,您还可以使用“toString()”“split()” :

let arrs = [
  ["$6"],
  ["$12"],
  ["$25"],
  ["$25"],
  ["$18"],
  ["$22"],
  ["$10"]
];

let newArr = arrs.toString().split(",");

console.log(newArr); // ["$6", "$12", "$25", "$25", "$18", "$22", "$10"]
Run Code Online (Sandbox Code Playgroud)

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

“join()”“split()”

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"]
Run Code Online (Sandbox Code Playgroud)

“toString()”“split()”

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"]
Run Code Online (Sandbox Code Playgroud)