携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第 16 天,点击查看活动详情
学习一下数组扁平化
start
- 经常看到有数组扁平化的题目。
- 看别人写的上来就好几种数组扁平化的方式,自己亲手写一写,变成自己的知识。
1. flat
ES6 在数组上新增的方法:Array.prototype.flat
;
const arr1 = [0, 1, 2, [3, 4]]
console.log(arr1.flat())
// expected output: [0, 1, 2, 3, 4]
const arr2 = [0, 1, 2, [[[3, 4]]]]
console.log(arr2.flat(2))
// expected output: [0, 1, 2, [3, 4]]
const arr3 = [0, 1, 2, [[[3, 4]]]]
console.log(arr3.flat(Infinity))
// expected output: [ 0, 1, 2, 3, 4 ]
个人总结
flat
:英文释义:平的,平坦的;arr.flat([depth])
, depth 指定要提取嵌套数组的结构深度,默认值为 1;- 返回一个包含将数组与子数组中所有元素的新数组;(扁平化不会修改原数组)
- 使用
Infinity
,可展开任意深度的嵌套数组; flat()
方法会移除数组中的空项:
2. toString + split + map
var arr = [1, 2, 3, [4, 5, [6, 7, 8]]]
var newArr = arr
.toString()
.split(',')
.map((item) => parseFloat(item))
个人总结
- 只针对纯数字的多维数组;
- 数组项存在字符串,例如:
[1,2,'3']
,使用这种方法,就会修改原数组; - map 的作用就是用来还原数组每一项的类型;
- 字符串转数组,方法很多:
parseFloat
,+
3. reduce + concat + isArray + recursivity(递归)
// 使用 reduce、concat 和递归展开无限多层嵌套的数组
var arr1 = [1, 2, 3, [1, 2, 3, 4, [2, 3, 4]]]
function flatDeep(arr, d = 1) {
return d > 0
? arr.reduce(
(acc, val) =>
acc.concat(Array.isArray(val) ? flatDeep(val, d - 1) : val),
[]
)
: arr.slice()
}
flatDeep(arr1, Infinity)
// [1, 2, 3, 1, 2, 3, 4, 2, 3, 4]
个人总结
- 主要思想就是递归;
- 其次就是 reduce 的基本用法;
- 再复习一下 reduce 的基础用法:
- 两个参数,一个参数为回调函数,一个参数为初始值;
- 回调函数的参数依次为:上一次调用的返回值;当前项;当前项索引;正在处理的数组;
4.forEach + isArray + push + recursivity(递归)
// forEach 遍历数组会自动跳过空元素
const eachFlat = (arr = [], depth = 1) => {
const result = [] // 缓存递归结果
// 开始递归
;(function flat(arr, depth) {
// forEach 会自动去除数组空位
arr.forEach((item) => {
// 控制递归深度
if (Array.isArray(item) && depth > 0) {
// 递归数组
flat(item, depth - 1)
} else {
// 缓存元素
result.push(item)
}
})
})(arr, depth)
// 返回递归结果
return result
}
// for of 循环不能去除数组空位,需要手动去除
const forFlat = (arr = [], depth = 1) => {
const result = []
;(function flat(arr, depth) {
for (let item of arr) {
if (Array.isArray(item) && depth > 0) {
flat(item, depth - 1)
} else {
// 去除空元素,添加非 undefined 元素
item !== void 0 && result.push(item)
}
}
})(arr, depth)
return result
}
个人总结
- 循环加递归;
- 需要注意的是 for 循环不会跳过空元素,forEach 会,例如:(
[1,,3].forEach(i=>{console.log('tomato',i)})
)。
5. 使用堆栈 stack
// 无递归数组扁平化,使用堆栈
// 注意:深度的控制比较低效,因为需要检查每一个值的深度
// 也可能在 shift / unshift 上进行 w/o 反转,但是末端的数组 OPs 更快
var arr1 = [1, 2, 3, [1, 2, 3, 4, [2, 3, 4]]]
function flatten(input) {
const stack = [...input]
const res = []
while (stack.length) {
// 使用 pop 从 stack 中取出并移除值
const next = stack.pop()
if (Array.isArray(next)) {
// 使用 push 送回内层数组中的元素,不会改动原始输入
stack.push(...next)
} else {
res.push(next)
}
}
// 反转恢复原数组的顺序
return res.reverse()
}
flatten(arr1) // [1, 2, 3, 1, 2, 3, 4, 2, 3, 4]
个人总结
- 基本原理就就是遇到数组就解构。
6. Use Generator
function
function* flatten(array) {
for (const item of array) {
if (Array.isArray(item)) {
yield* flatten(item)
} else {
yield item
}
}
}
var arr = [1, 2, [3, 4, [5, 6]]]
const flattened = [...flatten(arr)]
// [1, 2, 3, 4, 5, 6]
个人总结
- Generator 的说明
- flatten(arr)返回的是遍历器对象,然后通过解构运算符,依次执行。
- 本质还是递归的思想。
end
- 数组扁平化总结:
- 不修改原数组;
- 如果需要手写实现,优先考虑递归;