假如有个面试题:你能用多少种方法实现数组扁平化?
前言
什么是数组扁平化
数组扁平化是指将一个多维数组转换为一个一维数组的过程。
数组扁平化的五种方法
- 递归
- arr.flat(Infinity)
- toString --- 数组中只能有数字
- reduce --- 递归
- 解构 ...
递归
阶乘
例如:5! = 1 * 2 * 3 * 4 * 5,怎样通过一个方法实现阶乘?
for循环:
function mul(n) {
let res = 1
for(let i = 1; i <= n; i++) {
res *= i
}
return res
}
console.log(mul(5))
打印结果
递归
function mul(n) {
if(n == 1) return 1;
return n * mul(n - 1);
}
console.log(mul(5));
打印结果
分析
第五层会返回1,给到第四层mul(1),第四层的值会返回到第三层mul(2),以此类推得到结果。
注:if(n == 1) return 1;
这里必须要用到这行代码,不然mul()会被一直调用,mul(0)、mul(-1)、mul(-2)....直到爆栈。
递归函数两步走:
- 找好公式(如:
mul(n) = n * mul(n - 1)
) - 找到出口(如:
if(n == 1) return 1;
)
示例:
找到斐波那契数列第n个数:1 1 2 3 5 8 13 21 34 55 89 ...
第一步:fb(n) = fb(n - 1) + fb(n - 2)
,找到公式
第二步:if(n == 1 || n == 2) return 1
;找到出口
function fb(n) {
if(n ==1 || n == 2) return 1;
return fb(n - 1) + fb(n - 2)
}
console.log(fb(10))
打印结果
flat()
用于将多维数组扁平化,即把一个嵌套的数组转换为一维数组。
const arr = [1, 2, [3, 4, [5]]]
const newArr = arr.flat(3)
console.log(newArr)
打印结果
万一我们不知道这个数组嵌套了几层呢?
const arr = [1, 2, [3, 4, [5]]]
const newArr = arr.flat(Infinity)
console.log(newArr)
打印结果
分析
通过Infinity无穷大,无论数组嵌套多少层,都能将该数组扁平化。
面试的时候如果让你手搓一个函数实现数组扁平化呢?
先介绍一下concat方法和解构
concat()方法
concat()方法是用于将两个或者多个数组进行合并,返回一个新的数组,原数组不会被改变。
let arr = [1, 2, 3, 4, 5]
let arr2 = [6, 7, 8, 9, 10]
console.log(arr.concat(arr2), arr);
打印结果
concat也可将某个值直接放入数组中
解构
从数组或对象中提取值并将其分配给不同变量,...x
把剩余值以数组的形式赋给该变量,解构只能一层一层解。
let arr = [1, 2, 3, 4, 5]
let[a, b, ...arr2] = arr
console.log(a, b, arr2);
打印结果
也可使用解构来连接数组:
let arr = [1, 2, 3, 4, 5]
let arr2 = [6, 7, 8, 9]
let newArr = [...arr, ...arr2]
console.log(newArr);
打印结果
定义一个res空数组,使用一个for循环来遍历arr数组,再通过if判断语句,判断条件为Array.isArray(arr[i])
方法判断arr数组内部的元素是否为数组,若为数组则递归调用flatten方法,否则直接将arr数组的元素push到res数组中,并且将再次遍历到的结果添加到res数组上,每次遍历到的数组res为[1, 2],[3, 4], [5],并且每次调用该函数函数时都会将res数组连接起来。
通过concat()方法
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 = res.concat(flatten(arr[i]))
} else {
res.push(arr[i])
console.log(res);
}
}
return res
}
const newArr = flatten(arr)
console.log(newArr);
打印结果
通过解构方法
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 = [...res, ...flatten(arr[i])]
} else {
res.push(arr[i])
}
}
return res
}
const newArr = flatten(arr)
console.log(newArr);
打印结果
toString()和split()
- toString方法能将数组(无论嵌套多少层)转换为字符串
- 通过split方法以逗号为分隔符将上面的字符串变为数组
- 通过map遍历数组,将数组内的元素转为Number类型
const arr = [1, 2, [3, 4, [5]]]
let str = arr.toString()
const newArr = str.split(',').map((item) => {
return Number(item)
})
console.log(newArr);
打印结果
注:如果数组中元素类型不止有数字,不可使用toString()
const arr = [1, 2, 'abc', [3, 4, [5]]]
let str = arr.toString()
const newArr = str.split(',').map((item) => {
return Number(item)
})
console.log(newArr);
打印结果
reduce() -- 本质也是递归
也是遍历数组内元素的方法
array.reduce(callbackFn(pre, item, index, arr){}, initialValue)
分析
reduce()里面接收两个参数,一个是回调函数callbackFn() {}
,一个是initialValue
。
回调函数callbackFn里面接收四个参数:
- pre: 累计器累存回调的返回值;它是上一次调用回调时返回的累积值,或者是初始值(initialValue)。
- item: 数组里的每个元素的值。
- index: 当前遍历数组的索引。
- arr: 当前遍历的数组。
initialValue:作为第一次调用 callbackFn
函数时 pre
的值。如果省略,则 pre
的初始值为数组的第一个元素,item
从第二个元素开始。 通过reduce遍历该数组,pre为上一次reduce的结果,所以pre+item可以实现将所有的数组中的值相加起来,initialValue为0,即pre初始为0,pre+item-->0+1 1+2 3+3 6+4 10+5 15+6 21+7
,所以结果为28。
const arr = [1, 2, [3, 4, [5]]]
function flatten(arr) {
return arr.reduce((pre, item) => {
return pre.concat(Array.isArray(item) ? flatten(item) : item)
}, [])
}
console.log(flatten(arr));
打印结果
Array.isArray(item) ? flatten(item) : item
这是三元运算符,判断item
是否为数组,若是递归调用flatten()
函数,不是则把item
加入到pre
当中。
some()方法、解构和concat()方法实现数组扁平化
some(): 用于检测数组中的元素是否符合条件,数组中的至少有一个元素符合条件,符合返回true,否则,则返回false
let arr = [1, 2, 3, 4, 5, 6, 7]
let res = arr.some((item) => {
return item > 5
})
console.log(res);
打印结果
const arr = [1, 2, [3, 4, [5]]]
function flatten(arr) {
while(arr.some(item => Array.isArray(item))) {
arr = [].concat(...arr) // [].concat(1, 2, 3, 4, [5])
}
return arr
}
console.log(flatten(arr));
打印结果
分析
通过some
方法判断item
是否为数组,如果是则通过解构将item
解构再用concat
方法连接起来,[1, 2, [3, 4, [5]]] => [1, 2, 3, 4, [5]] => [ 1, 2, 3, 4, 5 ]
。
结语
学会这五种方法,面试还不得嘎嘎拿下。
转载自:https://juejin.cn/post/7372100118578757683