引言
本文介绍了将嵌套数组转换为一维数组的七种常见方法:flat()
方法、递归、toString()
方法、reduce()
方法、扩展运算符
、flatMap()
方法和堆栈
。简要分析了它们的优缺点,帮助读者选择最适合其情景的方法。
案例引入
简而言之,数组扁平化就是将一个多维数组变成一个一维数组,去除其中的嵌套数组,让数据变得更加扁平,方便处理和遍历。在实际开发中,经常需要对多维数组进行扁平化操作,例如处理JSON数据、递归操作等。
想象一下,你手头上有一个嵌套的数组,里面包含着各种各样的元素,而你现在需要将这个多层嵌套的数组整理成一个简单的一维数组。
初始:
const arr = [1, 2, [3, 4, [5]]]
变成:
[ 1, 2, 3, 4, 5 ]
常见数组扁平化方法
1. flat()方法
flat()
方法是ES6新增的数组方法,可以直接将多维数组一次性扁平化成指定深度的一维数组,非常方便。
优点:
- 简洁直观,易于使用。
- 性能优异,对于大部分情况都能有效处理。
缺点:
- 不支持浏览器兼容性较差的环境。
- 不能定制化处理,仅支持固定深度或无限深度。
const arr = [1, 2, [3, 4, [5]]]
const newArr = arr.flat(1) // 数组扁平化
const newArr1 = arr.flat(Infinity) //无穷大
console.log(newArr);
console.log(newArr1);
arr.flat(1)
展开一层嵌套数组。arr.flat(Infinity)
完全展开所有层级的嵌套数组。
2. 递归
递归是一种经典的扁平化方法,通过遍历数组的每一项,如果是数组则递归调用自身直到将所有元素提取出来。
优点:
- 逻辑清晰,容易理解。
- 适用于任意层级的数组。
缺点:
- 在深度层级非常高的情况下可能会导致栈溢出。
- 性能较差,尤其是对大型数组。
const arr = [1, 2, [3, 4, [5]]]
function flatten(arr) {
let res = []
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
res.push(...flatten(arr[i])) //递归
} else {
res.push(arr[i]);
}
}
return res;
}
const newArr = flatten(arr)
console.log(newArr);
递归执行过程概述:
-
最外层数组
[1, 2, [3, 4, [5]]]
传入flatten
函数:1
和2
被直接添加到结果数组res
。- 对
[3, 4, [5]]
递归调用flatten
。
-
在递归调用中
[3, 4, [5]]
被传入flatten
函数:3
和4
被直接添加到结果数组res
。- 对
[5]
递归调用flatten
。
-
在最内层递归调用中
[5]
被传入flatten
函数:5
被直接添加到结果数组res
。
-
最内层的
flatten
调用返回[5]
,中层递归合并得到[3, 4, 5]
,再返回至最外层,合并所有结果得到[1, 2, 3, 4, 5]
。
3. toString()方法
将数组转换成字符串,然后再通过split()方法拆分,最后再转换成数字类型,这样就可以实现数组扁平化了。
优点:
- 方法简单,代码短小。
缺点:
- 无法处理非数字数组元素。
- 会将非预期的字符类型也拆分。
- 性能较差。
const arr = [1, 2, [3, 4, [5]]]
let str = arr.toString() // '1,2,3,4,5'
const newArr = str.split(',').map((item) => {
return Number(item)
})
console.log(newArr);
arr
被转换为字符串'1,2,3,4,5'
。- 字符串根据逗号分割为数组
[ '1', '2', '3', '4', '5' ]
。 - 每个字符串元素被转换为数字类型,生成最终的数组
[1, 2, 3, 4, 5]
。
4. reduce() 方法
利用reduce()方法不断将数组拆分成单个元素,然后再合并起来,最终实现数组扁平化。
优点:
- 函数化编程方式,代码简洁。
- 可控制扁平化的过程。
缺点:
- 对于深层次数组性能一般。
- 代码可读性对于复杂嵌套的情况较差。
const arr = [1, 2, [3, 4, [5]]]
function flattenArray(arr) {
return arr.reduce((pre, val) => Array.isArray(val) ? pre.concat(flattenArray(val)) : pre.concat(val), []);
}
const newArr = flattenArray(arr);
console.log(newArr);
flattenArray函数的作用是使用 reduce
方法递归扁平化多层嵌套的数组。
-
reduce
方法传入初始值[]
,并通过累积器pre
和当前值val
进行迭代。 -
对于数组中的每个元素
val
,检查是否为数组:- 如果是数组,则递归调用
flattenArray(val)
直到所有嵌套数组被扁平化。 - 否则,将当前值
val
添加到累积器pre
中。
- 如果是数组,则递归调用
-
concat
方法用于连接累积器pre
和处理过的值,确保每个嵌套数组都被逐层展开。
5. 使用扩展运算符
通过ES6新增的扩展运算符,可以将多个数组“展开”成单个数组,实现扁平化的效果。
优点:
- 代码简洁、直观。
- 可处理任意深度的数组。
缺点:
- 在深层次数组的情况下性能较差。
- 不支持非常旧的浏览器环境。
const arr = [1, 2, [3, 4, [5]]]
function flattenArray(arr) {
while (arr.some(Array.isArray)) {
arr = [].concat(...arr);
}
return arr;
}
const newArr = flattenArray(arr);
console.log(newArr);
使用 while
循环来扁平化嵌套数组:
-
arr.some(Array.isArray)
:检查数组arr
中是否还存在数组。 -
[].concat(...arr)
:将嵌套数组展开一层,通过concat
和展开操作符...
实现。 -
循环会继续,直到所有嵌套的数组都被扁平化为一维数组。
[1, 2, [3, 4, [5]]] while一次变为 [1, 2, 3, 4, [5]]
6. flatMap() 方法
flatMap()
方法在将每个元素映射为一个新数组后,再将这些新数组“压缩”为一个新数组。
优点:
- 方法简洁,现代化。
- 可结合映射和扁平化的功能。
缺点:
- 不支持非常旧的浏览器环境。
- 需要自己实现递归逻辑。
const arr = [1, 2, [3, 4, [5]]]
function flattenArray(arr) {
return arr.flatMap(item => Array.isArray(item) ? flattenArray(item) : item);
}
const newArr = flattenArray(arr);
console.log(newArr);
flattenArray函数利用 flatMap
函数来扁平化嵌套数组:
-
flatMap
方法在映射每个元素时,会将返回的数组展开到一级,从而实现数组扁平化。 -
对于数组中的每个
item
,检查是否为数组:- 如果是数组,则递归调用
flattenArray(item)
直到所有嵌套数组被扁平化。 - 否则,返回当前元素
item
。
- 如果是数组,则递归调用
-
最终得到一个扁平化后的数组。
const arr = [1, 2, [3, 4, [5]]];
const newArr = arr.flatMap((x) => x);
console.log(newArr); // [ 1, 2, 3, 4, [ 5 ] ]
7. 堆栈(模拟递归)
使用堆栈的数据结构来模拟递归,将需要处理的数组不断压栈再出栈,直到最终扁平化。
优点:
- 不会导致栈溢出,适合非常深的数组。
- 性能较好,尤其是处理大型数组时。
缺点:
- 较复杂的实现方式,代码可读性稍差。
- 需要手动管理堆栈。
const arr = [1, 2, [3, 4, [5]]]
function flattenArray(arr) {
const stack = [...arr]; // 创建一个栈,初始时包含 arr 的所有元素
const result = []; // 存储扁平化后的结果数组
while (stack.length) {
const next = stack.pop(); // 从栈中取出下一个元素
// 如果下一个元素是数组,则将其展开,并放回栈中;否则放入结果数组的开头
Array.isArray(next) ? stack.push(...next) : result.unshift(next);
}
return result;
}
const newArr = flattenArray(arr);
console.log(newArr);
flattenArray函数利用栈数据结构来扁平化嵌套数组:
-
创建一个栈
stack
,初始时包含原始数组arr
的所有元素。 -
创建一个空数组
result
,用于存储扁平化后的结果。 -
在循环中,不断从栈中取出元素:
- 如果取出的元素是数组,则展开数组并放回栈;
- 如果不是数组,则将其放入结果数组的开头。
-
最终返回扁平化后的结果数组。
结语
在JavaScript中,数组扁平化是一个常见的操作,不同的方法适用于不同的情况。希望通过本篇文章的介绍,可以帮助你更加灵活地处理数组扁平化的问题。