前言
由于上半年参加了校招的技能面试, 前前后后面了20多个人了, 每次面试都会让应聘者手写一下数组扁平化flat()
,可是发现居然没有一个能够完成写出来, 所以打算总结一下假如遇到了数组扁平化的标题(也能够叫做手动封装flat()
办法),到底应该怎么写,怎么写能够得更高的分;
话不多说, 接下来我将站在面试官的视点剖析一切常见的完成办法, 并附上对应的得分状况: 五星打分制
满分: ⭐⭐⭐⭐⭐
标题
标题描绘:
已有多级嵌套数组 :
[1, [2, [3, [4, 5]]], 6]
将其扁平化处理
输出:[1,2,3,4,5,6]
什么是扁平化
界说 : 扁平化便是将多维数组变成一维数组,不存在数组的嵌套
完成扁平化的办法 封装 flatten
1. ES6 flat
flat(depth)
办法会按照一个可指定的深度递归遍历数组,并将一切元素与遍历到的子数组中的元素合并为一个新数组回来。
参数:
depth
(可选) 指定要提取嵌套数组的结构深度,默认值为 1
回来值:
回来一个新数组,包含数组与提取嵌套数组的一切元素的新数组
运用 Infinity
,可打开任意深度的嵌套数组
封装思路: 运用 es6 自带 API 处理
const arr = [1, [2, [3, [4, 5]]], 6]
function flatten(params) {
return params.flat(Infinity)
}
console.log(flatten(arr));
// 输出: [1,2,3,4,5,6]
得分 : ⭐
直接运用自带的办法能够很快的完成, 可是面试官当然不期望就看到这些呀 !
2. toString
假如数组的项全为数字,能够运用join(),toString()能够利用数组toString() 转为字符串
function flatten(arr) {
return arr.toString().split(',').map(item =>parseFloat(item))
}
console.log(flatten(arr));
// 输出:[ 1, 2, 3, 4, 5, 6 ]
得分 : ⭐ (并不是要考你的数组的办法调用)
3. 运用正则替换
看到嵌套的数组,假如在字符串的视点上看便是多了许多[
和]
,假如把它们替换就能够完成简单的扁平化
function flatten (arr) {
console.log('JSON.stringify(arr)', typeof JSON.stringify(arr))
let str= JSON.stringify(arr).replace(/([|])/g, '');
str = '[' + str + ']';
arr = JSON.parse(str);
return arr
}
console.log(flatten(arr))
**得分 : **⭐ (并不是要考你的数组的办法调用)
4. 循环递归
4.1 循环 + concat + push
当只要一层嵌套数组运用push的办法扁平化
[1, [2, 3,4,5,6]]
let result = [];
for (let i = 0; i < arr2.length; i++) {
result = result.concat((arr2[i]));
}
console.log(result);
[ 1, 2, 3, 4, 5, 6 ]
假如有多层嵌套的数组就需求运用 递归的思想 :
思路
- 循环判别数组的每一项是否是数组:
Array.isArray(arr[i])
- 是数组就递归调用上面的扁平化一层的代码
result = result.concat(flatten(arr[i]));
- 不是数组,直接经过push增加到回来值数组
function flatten(arr) {
let result = [];
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
result = result.concat(flatten(arr[i]));
} else {
result.push(arr[i])
}
}
return result
}
console.log(flatten(arr));
或许运用forEach
立即履行函数
// 递归版本的反嵌套
function flatten(array) {
var flattend = [];
(function flat(array) {
array.forEach(function(el) {
if (Array.isArray(el)) flat(el);
else flattend.push(el);
});
})(array);
return flattend;
}
当然循环能够更改成forEach循环,for of …等其他循环,简单的循环递归就能够一样的处理啦~
得分: ⭐⭐⭐ (能够运用递归写出数组扁平化,短少操控层级关系)
4.2 增加参数操控扁平化深度
这个能够理解为手写flat()
办法啦~
// 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;
}
得分: ⭐⭐⭐⭐ (能够运用递归写出数组扁平化,能够经过参数操控层级关系)
4.3 巧用 reduce
reduce
办法为数组中的每个元素按序履行一个reducer
函数,每一次运转 reducer 会将先前元素的核算结构作为参数传入,最后将其成果汇总为单个回来值
参数:
-
callbackFn
一个 reducer 函数,包含四个参数:
- previousVal :上一次调用
callbackFn
时的回来值,在第一次调用时,若指定了初始值initialValue
,previousVal 的值就位 initialValue,否则初始值便是为数组的索引为 0 的元素 -
currentVal
:数组中正在处理的元素,在第一次调用时,若指定了初始值,其值则为数组索引为 0 的元素 array[0],否则为 array[1] - currentIndex: 数组中正在处理的元素的索引,若指定了初始值 initialValue,则开始索引号为 0,否则从索引 1 开始
- array : 用于遍历的数组
-
initialValue
(可选) : 作为第一次调用 callback 函数时参数 previousValue 的值
回来值: 运用 reducer 回调函数遍历整个数组后的成果
思路:
当咱们运用 reduce 来解析第一层数组,能够得到:
const arr = [1, [[2, 3], 4],5]
const result = arr.reduce((acc, val) => acc.concat(val), []);
console.log(result);
// 输出: [1,[2,3],4,5]
能够看出上面的代码能够扁平化一层数组,关于多层级嵌套的数组, 这个时分就需求运用递归的思想来处理问题了,再次遍历数组,发现数组元素任然是数组的时分,再次履行上面扁平化
手写办法
const arr = [1, [[2, 3], 4],5]
const flatten = (arr, deep = 1) => {
if (deep <= 0) return arr;
return arr.reduce((res, curr) => res.concat(Array.isArray(curr) ? flatten(curr, deep - 1) : curr), [])
}
// function flatten (arr,deep=1) {
// return arr.reduce((acc,val) => acc.concat(Array.isArray(val)? flatten(val,deep-1):val),[])
// }
console.log(arr, Infinity);
// 输出:[ 1, 2, 3, 4, 5, 6 ]
得分: ⭐⭐⭐⭐ (能够运用递归写出数组扁平化,巧用reduce办法可加分)
4.4 运用 Generator
函数
GeneratorFunction是协程在 ES6 的完成,最大特点便是能够交出函数的履行权(即暂停履行)。
它不同于一般函数,是能够暂停履行的,所以函数名之前要加星号,以示差异。
整个 Generator 函数便是一个封装的异步使命,或许说是异步使命的容器。异步操作需求暂停的地方,都用 yield 语句注明。Generator 函数的履行办法如下。
结构器生成新的生成器函数
function* flatten(array) {
for (const item of array) {
if (Array.isArray(item)) {
yield* flatten(item);
} else {
yield item;
}
}
}
得分: ⭐⭐⭐ (运用Generator 函数 进行递归)
5. 运用仓库 stack 避免递归
递归循环都可经过保护一个堆结构来处理
假如不运用递归数组来完成扁平化,能够运用仓库来处理
深度的操控比较低效,由于需求检查每一个值的深度
思路:
- 把数组经过一个栈来保护
- 当栈不为空的时分循环履行处理
- pop()将栈尾出栈
- 假如出栈的元素是数组,就将该元素解构后每一元素进行入栈操作
- 出栈的元素不是数组就push进回来值res
- 回转恢复原数组的次序
var arr1 = [1,2,3,[1,2,3,4, [2,3,4]]];
function flatten(arr) {
const stack = [...arr];
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.while 循环+ some办法
some :办法测验数组中是不是至少有 1 个元素经过了被提供的函数测验。它回来的是一个 Boolean 类型的值。
思路
经过some来判别数组中是否用数组,经过while不断循环履行判别,
假如是数组的话能够运用 拓展运算符...
… 每次只能打开最外层的数组,加上contact
来削减嵌套层数,
function flatten(arr) {
while (arr.some(item=> Array.isArray(item))) {
console.log(...arr)
arr = [].concat(...arr)
console.log(arr)
}
return arr
}
console.log(flatten(arr));
得分: ⭐⭐⭐⭐ (运用while循环取消递归操作, 巧用some操作进行判别)
总结
完成数组扁平化的办法有许多, 评分也每个人有各自的看法, 欢迎我们在评论区留下你自己对每个完成办法的评分,一同学习沟通哦!
不会不要紧,最重要的是肯学
我们能够重视我的大众号:程序员Better 让咱们一同学习呀~
我正在参与技能社区创作者签约计划招募活动,点击链接报名投稿。
评论(0)