当前位置: 首页 > Web前端 > JavaScript

面试官:JavaScript是如何实现数组展平(flattening)的方法的?

时间:2023-03-27 10:13:06 JavaScript

采访者:JavaScript是如何实现数组展平(flattening)的方法的?1什么是数组展平?概念很简单,就是对一个“多维”数组进行降维,例如://原数组是一个“三维”数组constarray=[1,2,[3,4,[5,6],7],8,9]//可以降为二维newArray1=[1,2,3,4,[5,6],7,8,9]//也可以是降为一维newArray2=[1,2,3,4,5,6,7,8,9]数组扁平化也称为数组扁平化和数组降维。2JS标准库中的数组展平方法JavaScript标准库已经实现了数组展平的方法Array.prototype.flat()flat()方法会按照指定的深度递归遍历数组,并将所有元素与遍历到的元素组合起来子数组合并成一个新数组并返回。语法:varnewArray=arr.flat([depth])参数:depth为可选值,表示遍历多维数组的深度,默认值为1。可以理解为你要展开的层数(或降低维度)。返回值:由遍历的元素和子数组元素组成的新数组示例:constarray=[1,2,[3,4,[5,6],7],8,9]constnewArray1=array.flat()//相当于array.flat(1);将维度减少1//newArray1:[1,2,3,4,[5,6],7,8,9]constnewArray2=array.flat(2)//减少2个维度//newArray2:[1,2,3,4,5,6,7,8,9]特殊:当depth<=0时,返回的数组与原数组维度相同(注意只有维度相同,空缺见第3点)constarray=[1,2,[3,4,[5,6],7],8,9]array.flat(-1)//[1,2,[3,4,[5,6],7],8,9]depth=Infinity,返回的数组变成一维数组.flat(Infinity)//[1,2,3,4,5,6,7,8,9]有空隙在原始数组中,flat方法会消除间隙,即使flat(0)也会消除间隙,所以第一点说“只是相同的维度”。而flat方法扩展到哪一层,缝隙就消除到哪一层,更深的缝隙不消除constarray1=[1,,2,[3,,4,[5,6],7],8,9]//注意这个数组有两个空格array.flat(0)//[1,2,[3,,4,[5,6],7],8,9]//第一个空格不多了,第二个空缺还是3.实现一个flat方法flat方法扩展一层(减少1维)步骤:遍历数组,判断当前元素是否为数组,如果不是数组,直接保存;如果是数组,保存展开后保存平面方法。展开多层(降低多维性)无非是在展开一层的基础上使用递归对数组的子元素进行相同的操作。这个方法分为三个步骤:1.如何遍历数组2.如何判断一个元素是否为数组3.递归实现以上三个步骤,组合起来得到不同的平面实现3.1如何遍历数组方法有很多种,这里分为3类:1.for相关的for循环for...offor...in是为遍历对象属性而构建的,不建议与数组一起使用。constarray=[1,2,[3,4,[5,6],7],8,9]//for循环for(leti=0;i{});//reduce()array.reduce((pre,cur)=>{constelement=cur},[])//map()array.map(element=>{})3.数组方法:返回Iterator对象的方法keys()values()entries()//这三个方法只是获取遍历器对象,for...of遍历//keys()for(letiofarray.keys()){constelement=array[i]}//values()for(letelementofarray.values()){}//entries()for(let[i,element]ofarray.entries()){console.log(array[i])console.log(element)}3.2如何判断一个元素是否为数组设置一个变量a来判断是否为数组。这里有4个方法:Array有一个静态方法Array.isArray()来判断一个变量是否是一个数组。instanceof运算符用于检测构造函数的原型属性是否出现在实例对象的原型链上。如果a是一个数组,Array.prototype将出现在它的原型链上。通过对象的构造函数判断(该方法可能会失败,因为可以手动更改构造函数)通过Object.prototype.toString()判断,该方法可以返回一个代表ObjectString的值//Method1Array.isArray(a)//Method2ainstanceofArray//Method3a.constructor===Array//Method4//使用call调用Object.prototype上的toString方法Object.prototype。toString.call(a)==='[objectArray]'//不能这样判断,因为这个toString已经覆盖了Object.prototype.toString//只有Object.prototype.toString才能正确判断类型a.toString()3.3Recursion递归:对子元素进行同样的操作functionflat(){letres=[]遍历数组{if(当前元素是一个数组){flat(当前元素)得到一个一维数组并将一维数组拼接成res}else{res.push(currentelement)}}returnres}3.4flat方法的初步实现选择遍历方法和判断数组的方法,flat方法可以初步用递归实现,如:functionmyFlat(arr){letres=[];for(constitemofarr){if(Array.isArray(item)){res=res.concat(myFlat(item));//注意concat方法返回的是一个新数组,并没有改变原来的数组}else{res.推(项目);}}returnres;}myFlat方法可以将“多维”数组展平为一维数组,但不能指定展开深度depth,也不能处理数组空位。4优化4.1指定扩展深度处理扩展深度。简单,我们可以加一个递归终止条件,即depth<=0,代码如下:functionmyFlat(arr,depth=1){//如果depth<=0,直接返回if(depth<=0){returnarr}letres=[];for(constitemofarr){if(Array.isArray(item)){//对于每个递归调用,设置depth-1res=res.concat(myFlat(item,depth-1));}else{res.push(item);}}returnres;}4.2数组空位处理其实我们应该尽量避免数组空位的出现。我们提到了遍历数组的不同方法,它们对数组中的空白空间的处理方式不同。ForEach、reduce、map在遍历时会忽略空白;而对于。..of不会忽略它,它会在遇到间隙depth=1){if(depth<=0){returnarr;时将其视为未定义。}让res=[];for(constitemofarr){if(Array.isArray(item)){res=res.concat(myFlat(item,depth-1));}else{//判断数组空位item!==undefined&&res.push(item);}}returnres;}4.2.2forEach,map方法遍历当然你也可以使用forEach,map方法遍历数组,这样就不用手动判断了,但是这里要考虑一个特例,即当depth<=0时,我们使用filter方法将数组中的空位去掉//forEachfunctionmyFlat(arr,depth=1){if(depth<=0){returnarr.筛选r(项目=>项目!==未定义);}让res=[];arr.forEach((item)=>{if(Array.isArray(item)){res=res.concat(myFlat(item,depth-1));}else{res.push(item);}});returnres;}//mapfunctionmyFlat(arr,depth=1){if(depth<=0){returnarr.filter(item=>item!==undefined);}让res=[];arr.map((item)=>{if(Array.isArray(item)){res=res.concat(myFlat(item,depth-1));}else{res.push(item);}});returnres;}4.2.3reduce方法其中reduce方法最为简洁,也是面试中经常考的方法之一functionmyFlat(arr,depth=1){returndepth>0?arr.reduce((pre,cur)=>pre.concat(Array.isArray(cur)?myFlat(cur,depth-1):cur),[]):arr.filter((item)=>item!==undefined);}5Others5.1Stack理论上,递归方法通常可以转化为非递归方法,即使用stackfunctionmyFlat(arr){letres=[];常量堆栈=[]。连接(arr);while(stack.length>0){constitem=stack.流行音乐();如果(到达ay.isArray(item)){//使用扩展运算符展开一个层stack.push(...item);}else{item!==undefined&&res.unshift(item);}}returnres;}但是这个方法不能指定展开深度,只能完全展开成一维数组。5.2改进改进栈不能指定展开深度的缺点,代码如下:functionmyFlat(arr,depth=1){if(depth<=0){returnarr.filter((item)=>item!==未定义);}让res;让队列=[].concat(arr);while(depth>0){res=[];queue.forEach((item)=>{if(Array.isArray(item)){//注意,在用展开运算符展开数组之前,先用filter方法去掉空格res.push(...item.filter((e)=>e!==undefined));}else{res.push(item);}});深度-;队列=资源;}returnres;}公众号【前端】