我有一个 JavaScript 数组,例如:
[["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]
我将如何将单独的内部数组合并为一个:
["$6", "$12", "$25", ...]
我有一个 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);
console.log(merged);
使用 的apply
方法concat
只会将第二个参数作为一个数组,所以最后一行与此相同:
var merged2 = [].concat(["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]);
还有Array.prototype.flat()
一种方法(在 ES2019 中引入)可用于展平数组,尽管它仅在 Node.js 从版本 11 开始可用,而在 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);
这是一个简短的函数,它使用一些较新的 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 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), []);
有一种称为flat的新本地方法可以准确地做到这一点。
(截至 2019 年底,flat
现已在 ECMA 2019 标准中发布,并且core-js@3
(babel 的库)将其包含在他们的 polyfill库中)
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];
这里的大多数答案都不适用于大型(例如 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;
};
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 flatten(arr) {
return [].concat(...arr)
}
Is 只是扩展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
)
)
}
请参阅JSBin上的演示。
此答案中使用的 ECMAScript 6 元素的参考:
旁注:find()
并非所有浏览器都支持方法和箭头函数,但这并不意味着您现在不能使用这些功能。只需使用Babel——它将 ES6 代码转换为 ES5。
您可以使用下划线:
var x = [[1], [2], [3, 4]];
_.flatten(x); // => [1, 2, 3, 4]
通用过程意味着我们不必在每次需要使用特定行为时重写复杂性。
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))
是的,你猜对了,它只变平了一层,这正是它应该如何工作的
想象一些这样的数据集
// 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 ] ] ]
好的,现在说我们要打印一份名单,显示所有将参加的球员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 ]
这并不是说有时您也不想展平嵌套数组——只是这不应该是默认行为。
我们可以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 ]
那里。现在每个作业都有一个工具——一个用于挤压一层嵌套,flatten
一个用于消除所有嵌套deepFlatten
。
也许你可以打电话给它,obliterate
或者nuke
如果你不喜欢这个名字deepFlatten
。
不要重复两次!
当然,上面的实现既聪明又简洁,但是使用 a.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 -> 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 ]
要展平单个元素数组的数组,您不需要导入库,简单的循环是最简单和最有效的解决方案:
for (var i = 0; i < a.length; i++) {
a[i] = a[i][0];
}
致反对者:请阅读问题,不要反对,因为它不适合您非常不同的问题。对于所提出的问题,此解决方案是最快和最简单的。
更一般情况下的解决方案,当您的数组中可能有一些非数组元素时。
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;
}
reduce(callback[, initialValue])
使用方法怎么样JavaScript 1.8
list.reduce((p,n) => p.concat(n),[]);
会做这项工作。
函数式风格的另一个 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 提案)。感谢@(Константин Ван) 和@(Mark Amery) 在评论中提到它。
该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.flat()
方法。它以下列方式工作:
let arr = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]].flat()
console.log(arr);
该flat()
方法创建一个新数组,其中所有子数组元素递归连接到其中,直到 1 层深度(即数组内的数组)
如果您还想展平 3 维甚至更高维的数组,您只需多次调用 flat 方法。例如(3 个维度):
let arr = [1,2,[3,4,[5,6]]].flat().flat().flat();
console.log(arr);
Array.flat()
方法比较新。像 ie 这样的旧浏览器可能没有实现该方法。如果您希望您的代码可以在所有浏览器上工作,您可能必须将您的 JS 转换为旧版本。检查MDN Web 文档以了解当前浏览器的兼容性。
const common = arr.reduce((a, b) => [...a, ...b], [])
您可以将Array.flat()
withInfinity
用于任何深度的嵌套数组。
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)
在此处查看浏览器兼容性
请注意:当使用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));
一旦你习惯了柯里化形式的小箭头函数、函数组合和高阶函数,这段代码读起来就像散文一样。然后,编程仅包括将始终按预期工作的小构建块组合在一起,因为它们不包含任何副作用。
见lodash flatten,underscore flatten (浅true
)
function flatten(arr) {
return arr.reduce((acc, e) => acc.concat(e), []);
}
function flatten(arr) {
return [].concat.apply([], arr);
}
经测试
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]);
});
function flattenDeep(arr) {
return arr.reduce((acc, e) => Array.isArray(e) ? acc.concat(flattenDeep(e)) : acc.concat(e), []);
}
经测试
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]);
});
使用扩展运算符:
const input = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]];
const output = [].concat(...input);
console.log(output); // --> ["$6", "$12", "$25", "$25", "$18", "$22", "$10"]
如果您只有包含 1 个字符串元素的数组:
[["$6"], ["$12"], ["$25"], ["$25"]].join(',').split(',');
将完成这项工作。与您的代码示例特别匹配的 Bt。
我推荐一个节省空间的生成器函数:
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);
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
用于 N 次嵌套数组的 ES3 后备功能的ES5 方式:
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));
我已经使用递归和闭包完成了它
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;
}
var array = [["$6"], ["$12","$16"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]
var a = array.flat(Infinity);
console.log(a);
前几天我在玩ES6 Generators并写了这个 gist。其中包含...
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);
基本上,我正在创建一个循环遍历原始输入数组的生成器,如果它找到一个数组,它将使用yield*运算符与递归相结合,以不断展平内部数组。如果该项目不是一个数组,它只会产生单个项目。然后使用ES6 Spread 运算符(又名 splat 运算符),我将生成器展平为一个新的数组实例。
我还没有测试过它的性能,但我认为这是使用生成器和 yield* 运算符的一个很好的简单示例。
但同样,我只是在胡说八道,所以我确信有更多高效的方法可以做到这一点。
只是没有 lodash 的最佳解决方案
let flatten = arr => [].concat.apply([], arr.map(item => Array.isArray(item) ? flatten(item) : item))
我宁愿将整个数组按原样转换为字符串,但与其他答案不同,会使用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)
这并不难,只需遍历数组并合并它们:
var result = [], input = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"]];
for (var i = 0; i < input.length; ++i) {
result = result.concat(input[i]);
}
看起来这看起来像是 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);
}
};
用法:
flatten([1,[2,3],4,[[5,6],7]]);
// Result: [1, 2, 3, 4, 5, 6, 7]
如果你使用 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)
我认为 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))
这是递归方式...
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]
这是Typescript中最快的解决方案,它也适用于具有多级嵌套的数组:
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));
我提出了两个没有递归的简短解决方案。从计算复杂度的角度来看,它们并不是最优的,但在一般情况下工作正常:
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));
}
这里的逻辑是将输入数组转换为字符串并删除所有括号([])并将输出解析为数组。我为此使用了 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)
// 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)
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]
好吧,如果您的编码环境支持 ES6 (ES2015),您无需编写任何递归函数或使用 map、reduce 等数组方法。
一个简单的扩展运算符(...) 将帮助您将数组的数组展平为单个数组
例如:
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]
这是现代浏览器的另一个深度扁平化:
function flatten(xs) {
xs = Array.prototype.concat.apply([], xs);
return xs.some(Array.isArray) ? flatten(xs) : xs;
};
如今,最好和最简单的方法是像这样加入和拆分阵列。
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.apply([], arrays);
为 [].concat(...arrays);
var flattened = [].concat(...input);
编辑最有效的解决方案
解决问题的最有效方法是使用循环。您可以在此处比较“操作/秒”速度
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]);
}
希望能帮助到你
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 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
}
只是为了增加伟大的解决方案。我使用递归来解决这个问题。
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;
}
}
最好以递归方式进行,因此如果另一个数组中还有另一个数组,则可以轻松过滤...
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 版本,flatMap
为 Scala 粉丝提供了额外的实现。
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>());
}
只需使用扩展运算符,我们就可以通过以下方式展平。
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]
如果你的数组只包含整数或字符串,你可以使用这个肮脏的技巧:
var arr = [345,2,[34],2,[524,[5456]],[5456]];
var flat = arr.toString().split(',');
有效,在 FF、IE 和 Chrome 中还没有测试其他浏览器。
要在一行中展平二维数组:
[[1, 2], [3, 4, 5]].reduce(Function.prototype.apply.bind(Array.prototype.concat))
// => [ 1, 2, 3, 4, 5 ]
我知道这是 hacky,但是我知道的将字符串数组(任何深度!)展平(不带逗号!)的必须简洁的方法是将数组转换为字符串,然后用逗号分割字符串:
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]
适用于所有数据类型的递归版本
/*jshint esversion: 6 */
// nested array for testing
let 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 array
flatten(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]);
}, []);
}
以下代码将展平深度嵌套的数组:
/**
* [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)
因此,随着您的嵌套增加,您可以继续增加数量。
例如:
[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>
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
我写的简单的扁平化工具
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 引入了 flat 和 flatMap,那么 flat 任何数组都可以这样完成:
const myArr = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]
const myArrFlat= myArr.flat(Infinity);
console.log(myArrFlat); // ["$6", "$12", "$25", ...]
参考。https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat
递归调用该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);
}
使用此方法将两个数组展平
arr1.concat(...arr2);
这是使用堆栈进行非递归展平深度的解决方案。
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);
[1,[2,3],[4,[5,6]]].reduce(function(p, c) {
return p.concat(c instanceof Array ?
c.reduce(arguments.callee, []) :
[c]);
}, []);
这是我的版本。它允许您展平可用于更多场景的复杂对象:
输入
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]
与使用最佳答案中列出的 merge.concat.apply() 方法相比,有一种更快的方法,而且更快是指速度快几个数量级。这假设您的环境可以访问 ES5 数组方法。
var array2d = [
["foo", "bar"],
["baz", "biz"]
];
merged = array2d.reduce(function(prev, next) {
return prev.concat(next);
});
这是 jsperf 链接:http: //jsperf.com/2-dimensional-array-merge
如果您需要支持 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 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);
您可以使用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
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
我最初想使用该.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 创建新数组,也不是递归调用任何函数。
我有一个简单的解决方案,无需使用特殊的 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]);
}
使用 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"]
const arr = [1, 2, [3, 4]];
arr.reduce((acc, val) => acc.concat(val), []);
您可以使用"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"]
此外,您还可以使用“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"]
但是,如果字符串包含逗号,上述两种方法都不能正常工作:
“加入()”和“分裂()”:
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"]
“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"]
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));
Array.prototype.flatten = Array.prototype.flatten || function() {
return [].reduce.call(this, function(flat, toFlatten) {
return flat.concat(Array.isArray(toFlatten) ? toFlatten.flatten() : toFlatten);
},[])
};
我只是用 来回答这个问题ES6
,假设深度数组是:
const deepArray = ['1',[['a'],['b']],[2],[[[['4',[3,'c']]]],[5]]];
如果您知道或猜测您的数组的深度不超过一个数字7
,请使用以下代码:
const flatArray = deepArray.flat(7);
但是如果你不知道你的深度数组的深度或者你的JavaScript
引擎不支持flat
like react-native
JavaScriptCore
,请使用下面的JavaScript
reduce
函数:
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]
更简单直接的一个;可选择深度压平;
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
[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]
如果所有数组元素都是 Integer,Float,... 或/和 String ,那么就这样做吧:
var myarr=[1,[7,[9.2]],[3],90];
eval('myarr=['+myarr.toString()+']');
print(myarr);
// [1, 7, 9.2, 3, 90]
我相信最好的方法是这样的:
var flatten = function () {
return [].slice.call(arguments).toString().split(',');
};
我只是在寻找更快更简单的解决方案来做到这一点,为什么?因为我把这个作为一个面试问题,我很好奇,所以我做了这个:
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 now
console.time("flatten");
output = new Array(JSON.stringify(i).replace(/[^\w\s,]/g,""));
output
// ... and stop.
console.timeEnd("flatten");
// Start timing now
console.time("flatten2");
output = [].concat.apply([], i)
output
// ... and stop.
console.timeEnd("flatten2");
// Start timing now
console.time("flatten3");
output = flattenArrayOfArrays(i)
output
// ... and stop.
console.timeEnd("flatten3");
我在这里使用了最受欢迎的答案和我的解决方案。我想有人会觉得这很有趣。干杯!
ES6 的纯粹魔法
const flat = A => A.reduce((A, a) => Array.isArray(a) ? [...A, ...flat(a)] : [...A, a], []);