[前端] JS前端面试数组扁平化手写flat函数示例

2428 0
Honkers 2022-10-21 15:50:06 | 显示全部楼层 |阅读模式
目录

    前言题目 实现扁平化的方法 封装 flatten1. ES6 flat2. toString3. 使用正则替换4. 循环递归
      4.1 循环 + concat + push4.2 增加参数控制扁平化深度4.3 巧用 reduce4.4 使用 Generator 函数
    5. 使用堆栈 stack 避免递归6.while 循环+ some方法


前言

由于上半年参加了校招的技术面试, 前前后后面了20多个人了, 每次面试都会让应聘者手写一下数组扁平化flat(),但是发现居然没有一个能够完成写出来, 所以打算总结一下如果遇到了数组扁平化的题目(也可以叫做手动封装flat()方法),到底应该怎么写,怎么写可以得更高的分;
话不多说, 接下来我将站在面试官的角度分析所有常见的实现方法, 并附上对应的得分情况: 五星打分制
满分:

题目 实现扁平化的方法 封装 flatten

题目描述:
已有多级嵌套数组 : [1, [2, [3, [4, 5]]], 6] 将其扁平化处理 输出: [1,2,3,4,5,6]
什么是扁平化
定义 : 扁平化就是将多维数组变成一维数组,不存在数组的嵌套

1. ES6 flat

flat(depth) 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。
参数:
depth(可选) 指定要提取嵌套数组的结构深度,默认值为 1
返回值:
返回一个新数组,包含数组与提取嵌套数组的所有元素的新数组
使用 Infinity,可展开任意深度的嵌套数组
封装思路: 使用 es6 自带 API 处理
  1. const arr = [1, [2, [3, [4, 5]]], 6]
  2. function flatten(params) {
  3.    return params.flat(Infinity)
  4. }
  5. console.log(flatten(arr));
  6. // 输出: [1,2,3,4,5,6]
复制代码
得分 :
直接使用自带的方法可以很快的实现, 但是面试官当然不希望就看到这些呀 !

2. toString

如果数组的项全为数字,可以使用join(),toString()可以利用数组toString() 转为字符串
  1. function flatten(arr) {
  2.   return arr.toString().split(',').map(item =>parseFloat(item))
  3. }
  4. console.log(flatten(arr));
  5. // 输出:[ 1, 2, 3, 4, 5, 6 ]
复制代码
得分 :  (并不是要考你的数组的方法调用)

3. 使用正则替换

看到嵌套的数组,如果在字符串的角度上看就是多了很多[ 和],如果把它们替换就可以实现简单的扁平化
  1. function flatten (arr) {
  2.   console.log('JSON.stringify(arr)', typeof JSON.stringify(arr))
  3.   let str= JSON.stringify(arr).replace(/(\[|\])/g, '');
  4.   str = '[' + str + ']';
  5.   arr = JSON.parse(str);
  6.   return arr
  7. }
  8. console.log(flatten(arr))
复制代码
得分 :  (并不是要考你的数组的方法调用)

4. 循环递归


4.1 循环 + concat + push

当只有一层嵌套数组使用push的方式扁平化
[1, [2, 3,4,5,6]]
  1. let result = [];
  2. for (let i = 0; i < arr2.length; i++) {
  3.   result = result.concat((arr2[i]));
  4. }
  5. console.log(result);
  6. [ 1, 2, 3, 4, 5, 6 ]
复制代码
如果有多层嵌套的数组就需要使用 递归的思想 :
思路
    循环判断数组的每一项是否是数组: Array.isArray(arr)是数组就递归调用上面的扁平化一层的代码 result = result.concat(flatten(arr));不是数组,直接通过push添加到返回值数组
  1. function flatten(arr) {
  2.   let result = [];
  3.   for (let i = 0; i < arr.length; i++) {
  4.     if (Array.isArray(arr[i])) {
  5.       result = result.concat(flatten(arr[i]));
  6.     } else {
  7.       result.push(arr[i])
  8.     }
  9.   }
  10.   return result
  11. }
  12. console.log(flatten(arr));
复制代码
或者使用forEach 立即执行函数
  1. // 递归版本的反嵌套
  2. function flatten(array) {
  3.   var flattend = [];
  4.   (function flat(array) {
  5.     array.forEach(function(el) {
  6.       if (Array.isArray(el)) flat(el);
  7.       else flattend.push(el);
  8.     });
  9.   })(array);
  10.   return flattend;
  11. }
复制代码
当然循环可以更改成forEach循环,for of ...等其他循环,简单的循环递归就能够一样的解决啦~
得分:  (能够使用递归写出数组扁平化,缺少控制层级关系)

4.2 增加参数控制扁平化深度

这个可以理解为手写flat()方法啦~
  1. // forEach 遍历数组会自动跳过空元素
  2. const eachFlat = (arr = [], depth = 1) => {
  3.   const result = []; // 缓存递归结果
  4.   // 开始递归
  5.   (function flat(arr, depth) {
  6.     // forEach 会自动去除数组空位
  7.     arr.forEach((item) => {
  8.       // 控制递归深度
  9.       if (Array.isArray(item) && depth > 0) {
  10.         // 递归数组
  11.         flat(item, depth - 1)
  12.       } else {
  13.         // 缓存元素
  14.         result.push(item)
  15.       }
  16.     })
  17.   })(arr, depth)
  18.   // 返回递归结果
  19.   return result;
  20. }
  21. // for of 循环不能去除数组空位,需要手动去除
  22. const forFlat = (arr = [], depth = 1) => {
  23.   const result = [];
  24.   (function flat(arr, depth) {
  25.     for (let item of arr) {
  26.       if (Array.isArray(item) && depth > 0) {
  27.         flat(item, depth - 1)
  28.       } else {
  29.         // 去除空元素,添加非 undefined 元素
  30.         item !== void 0 && result.push(item);
  31.       }
  32.     }
  33.   })(arr, depth)
  34.   return result;
  35. }
复制代码
得分:  (能够使用递归写出数组扁平化,可以通过参数控制层级关系)

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 来解析第一层数组,可以得到:
  1. const arr = [1, [[2, 3], 4],5]
  2. const result = arr.reduce((acc, val) => acc.concat(val), []);
  3. console.log(result);
  4. // 输出: [1,[2,3],4,5]
复制代码
可以看出上面的代码可以扁平化一层数组,对于多层级嵌套的数组, 这个时候就需要使用递归的思想来解决问题了,再次遍历数组,发现数组元素任然是数组的时候,再次执行上面扁平化
手写方法
  1. const arr = [1, [[2, 3], 4],5]
  2. function flatten (arr,deep=1) {
  3. return   arr.reduce((acc,val) => acc.concat(Array.isArray(val)? flatten(val,deep-1):val),[])
  4. }
  5. console.log(arr, Infinity);
  6. // 输出:[ 1, 2, 3, 4, 5, 6 ]
复制代码
得分:  (能够使用递归写出数组扁平化,巧用reduce方法可加分)

4.4 使用 Generator 函数

GeneratorFunction是协程在 ES6 的实现,最大特点就是可以交出函数的执行权(即暂停执行)。
它不同于普通函数,是可以暂停执行的,所以函数名之前要加星号,以示区别。
整个 Generator 函数就是一个封装的异步任务,或者说是异步任务的容器。异步操作需要暂停的地方,都用 yield 语句注明。Generator 函数的执行方法如下。
构造器生成新的生成器函数
  1. function* flatten(array) {
  2.     for (const item of array) {
  3.         if (Array.isArray(item)) {
  4.             yield* flatten(item);
  5.         } else {
  6.             yield item;
  7.         }
  8.     }
  9. }
复制代码
得分:  (使用Generator 函数 进行递归)

5. 使用堆栈 stack 避免递归

递归循环都可通过维护一个堆结构来解决
如果不使用递归数组来实现扁平化,可以使用堆栈来解决
深度的控制比较低效,因为需要检查每一个值的深度
思路:
    把数组通过一个栈来维护当栈不为空的时候循环执行处理pop()将栈尾出栈如果出栈的元素是数组,就将该元素解构后每一元素进行入栈操作出栈的元素不是数组就push进返回值res反转恢复原数组的顺序
  1. var arr1 = [1,2,3,[1,2,3,4, [2,3,4]]];
  2. function flatten(arr) {
  3.   const stack = [...arr];
  4.   const res = [];
  5.   while (stack.length) {
  6.     // 使用 pop 从 stack 中取出并移除值
  7.     const next = stack.pop();
  8.     if (Array.isArray(next)) {
  9.       // 使用 push 送回内层数组中的元素,不会改动原始输入
  10.       stack.push(...next);
  11.     } else {
  12.       res.push(next);
  13.     }
  14.   }
  15.   // 反转恢复原数组的顺序
  16.   return res.reverse();
  17. }
  18. flatten(arr1);// [1, 2, 3, 1, 2, 3, 4, 2, 3, 4]
复制代码
得分:  (使用数据结构栈的特性取代递归操作,减少时间复杂度)

6.while 循环+ some方法

some :方法试数组中是不是至少有 1 个元素通过了被提供的函数测试。它返回的是一个 Boolean 类型的值。
思路
通过some来判断数组中是否用数组,通过while不断循环执行判断, 如果是数组的话可以使用 拓展运算符... ... 每次只能展开最外层的数组,加上contact来减少嵌套层数,
  1. function flatten(arr) {
  2.   while (arr.some(item=> Array.isArray(item))) {
  3.     console.log(...arr)
  4.     arr = [].concat(...arr)
  5.     console.log(arr)
  6.   }
  7.   return arr
  8. }
  9. console.log(flatten(arr));
复制代码
得分:  (使用while循环取消递归操作, 巧用some操作进行判断)
以上就是JS前端面试数组扁平化手写flat函数示例的详细内容,更多关于JS数组扁平化flat函数的资料请关注中国红客联盟其它相关文章!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Honkers

荣誉红客

关注
  • 4009
    主题
  • 36
    粉丝
  • 0
    关注
这家伙很懒,什么都没留下!

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2025 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行