Javascript 合并/展平数组数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10865025/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Merge/flatten an array of arrays
提问by Andy
I have a JavaScript array like:
我有一个 JavaScript 数组,如:
[[""], [""], [""], [""], [""], [""], [""]]
How would I go about merging the separate inner arrays into one like:
我将如何将单独的内部数组合并为一个,例如:
["", "", "", ...]
回答by Gumbo
You can use concat
to merge arrays:
您可以使用concat
合并数组:
var arrays = [
[""],
[""],
[""],
[""],
[""],
[""],
[""]
];
var merged = [].concat.apply([], arrays);
console.log(merged);
Using the apply
method of concat
will just take the second parameter as an array, so the last line is identical to this:
使用 的apply
方法concat
只会将第二个参数作为数组,因此最后一行与此相同:
var merged2 = [].concat([""], [""], [""], [""], [""], [""], [""]);
There is also the Array.prototype.flat()
method (introduced in ES2019) which you could use to flatten the arrays, although it is only available in Node.js starting with version 11, and not at all in Internet Explorer.
还有Array.prototype.flat()
一种方法(在 ES2019 中引入)可用于展平数组,尽管它仅在 Node.js 版本 11 开始可用,而在 Internet Explorer 中根本不可用。
const arrays = [
[""],
[""],
[""],
[""],
[""],
[""],
[""]
];
const merge3 = arrays.flat(1); //The depth level specifying how deep a nested array structure should be flattened. Defaults to 1.
console.log(merge3);
回答by Noah Freitas
Here's a short function that uses some of the newer JavaScript array methods to flatten an n-dimensional array.
这是一个简短的函数,它使用一些较新的 JavaScript 数组方法来展平 n 维数组。
function flatten(arr) {
return arr.reduce(function (flat, toFlatten) {
return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
}, []);
}
Usage:
用法:
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]
回答by Nikita Volkov
There is a confusingly hidden method, which constructs a new array without mutating the original one:
有一种令人困惑的隐藏方法,它在不改变原始数组的情况下构造一个新数组:
var oldArray = [[1],[2,3],[4]];
var newArray = Array.prototype.concat.apply([], oldArray);
console.log(newArray); // [ 1, 2, 3, 4 ]
回答by user2668376
It can be best done by javascript reduce function.
最好通过 javascript reduce 函数来完成。
var arrays = [[""], [""], [""], [""], [""], [""], [""], ["arrays = arrays.reduce((a, b) => a.concat(b), []);
"], [""],[""], [""], [""], ["0"], [""], [""], [""], [""]];
arrays = arrays.reduce(function(a, b){
return a.concat(b);
}, []);
Or, with ES2015:
或者,使用 ES2015:
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];
回答by Alister
There's a new native method called flatto do this exactly.
有一种称为flat的新本地方法可以准确地做到这一点。
(As of late 2019, flat
is now published in the ECMA 2019 standard, and core-js@3
(babel's library) includes it in their polyfill library)
(截至 2019 年底,flat
现已在 ECMA 2019 标准中发布,并且core-js@3
(babel 的库)将其包含在他们的 polyfill库中)
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;
};
回答by Micha? Per?akowski
Most of the answers here don't work on huge (e.g. 200 000 elements) arrays, and even if they do, they're slow. polkovnikov.ph's answerhas the best performance, but it doesn't work for deep flattening.
这里的大多数答案不适用于大型(例如 200 000 个元素)数组,即使它们适用,它们也很慢。polkovnikov.ph 的答案具有最佳性能,但它不适用于深度扁平化。
Here is the fastest solution, which works also on arrays with multiple levels of nesting:
这是最快的解决方案,它也适用于具有多级嵌套的数组:
flatten(Array(200000).fill([1]));
Examples
例子
Huge arrays
巨大的数组
flatten(Array(2).fill(Array(2).fill(Array(2).fill([1]))));
It handles huge arrays just fine. On my machine this code takes about 14 ms to execute.
它可以很好地处理巨大的数组。在我的机器上,此代码执行大约需要 14 毫秒。
Nested arrays
嵌套数组
flatten([1, [1], [[1]]]);
It works with nested arrays. This code produces [1, 1, 1, 1, 1, 1, 1, 1]
.
它适用于嵌套数组。此代码生成[1, 1, 1, 1, 1, 1, 1, 1]
.
Arrays with different levels of nesting
具有不同嵌套级别的数组
function flatten(arr) {
return [].concat(...arr)
}
It doesn't have any problems with flattening arrays like this one.
像这样的展平阵列没有任何问题。
回答by Micha? Per?akowski
Update: it turned out that this solution doesn't work with large arrays. It you're looking for a better, faster solution, check out this answer.
更新:事实证明,此解决方案不适用于大型阵列。如果您正在寻找更好、更快的解决方案,请查看此答案。
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
)
)
}
Is simply expands arr
and passes it as arguments to concat()
, which merges all the arrays into one. It's equivalent to [].concat.apply([], arr)
.
Is 只是扩展arr
并将其作为参数传递给concat()
,这将所有数组合并为一个。它相当于[].concat.apply([], arr)
.
You can also try this for deep flattening:
您也可以尝试使用此方法进行深度展平:
var x = [[1], [2], [3, 4]];
_.flatten(x); // => [1, 2, 3, 4]
See demo on JSBin.
请参阅JSBin 上的演示。
References for ECMAScript 6 elements used in this answer:
此答案中使用的 ECMAScript 6 元素的参考资料:
Side note: methods like find()
and arrow functions are not supported by all browsers, but it doesn't mean that you can't use these features right now. Just use Babel— it transforms ES6 code into ES5.
旁注:find()
并非所有浏览器都支持像箭头函数这样的方法,但这并不意味着您现在不能使用这些功能。只需使用Babel——它将 ES6 代码转换为 ES5。
回答by Todd Yandell
You can use Underscore:
您可以使用下划线:
// 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 =
[[""], [""], [""], [""], [""], [""], [""]]
console.log (flatten (data))
回答by Thank you
Generic procedures mean we don't have to rewrite complexity each time we need to utilize a specific behaviour.
通用过程意味着我们不必在每次需要利用特定行为时重写复杂性。
concatMap
(or flatMap
) is exactly what we need in this situation.
concatMap
(或flatMap
) 正是我们在这种情况下所需要的。
// 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 ] ] ]
foresight
远见
And yes, you guessed it correctly, it only flattens onelevel, which is exactly how it shouldwork
是的,你猜对了,它只是变得平坦一个水平,而这正是它是如何应工作
Imagine some data set like this
想象一些这样的数据集
const gamePlayers = game =>
flatten (game)
gamePlayers (game)
// => [ [ 'bob', 5 ], [ 'alice', 6 ], [ 'ricky', 4 ], [ 'julian', 2 ] ]
Ok, now say we want to print a roster that shows all the players that will be participating in game
…
好的,现在假设我们要打印一个名单,显示所有将参加的球员game
......
const gamePlayers = game =>
badGenericFlatten(game)
gamePlayers (game)
// => [ 'bob', 5, 'alice', 6, 'ricky', 4, 'julian', 2 ]
If our flatten
procedure flattened nested arrays too, we'd end up with this garbage result …
如果我们的flatten
过程也扁平化嵌套数组,我们最终会得到这个垃圾结果......
// 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 ]
rollin' deep, baby
滚得很深,宝贝
That's not to say sometimes you don't want to flatten nested arrays, too – only that shouldn't be the default behaviour.
这并不是说有时您也不想展平嵌套数组——只是这不应该是默认行为。
We can make a deepFlatten
procedure with ease …
我们可以轻松制作一个deepFlatten
程序……
// 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 ]
There. Now you have a tool for each job – one for squashing one level of nesting, flatten
, and one for obliterating all nesting deepFlatten
.
那里。现在您为每项工作提供了一个工具——一个用于压缩一层嵌套,flatten
另一个用于消除所有嵌套deepFlatten
。
Maybe you can call it obliterate
or nuke
if you don't like the name deepFlatten
.
也许你可以叫它,obliterate
或者nuke
如果你不喜欢这个名字deepFlatten
。
Don't iterate twice !
不要重复两次!
Of course the above implementations are clever and concise, but using a .map
followed by a call to .reduce
means we're actually doing more iterations than necessary
当然,上面的实现既聪明又简洁,但是使用.map
后跟调用.reduce
意味着我们实际上进行了比必要更多的迭代
Using a trusty combinator I'm calling mapReduce
helps keep the iterations to a minium; it takes a mapping function m :: a -> b
, a reducing function r :: (b,a) ->b
and returns a new reducing function - this combinator is at the heart of transducers; if you're interested, I've written other answers about them
使用我调用的可靠组合器mapReduce
有助于将迭代保持在最小值;它需要一个映射函数m :: a -> b
、一个归约函数r :: (b,a) ->b
并返回一个新的归约函数——这个组合子是转换器的核心;如果你有兴趣,我已经写了关于它们的其他答案
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;
}
回答by Trindaz
A solution for the more general case, when you may have some non-array elements in your array.
更一般情况的解决方案,当您的数组中可能有一些非数组元素时。
##代码##