当前位置: 首页 > 后端技术 > Node.js

你不得不知道的25个arrayreduce高级用法

时间:2023-04-03 10:10:38 Node.js

作者:JowayYoung仓库:Github、CodePen博客:官网、掘金、ThinkNo、知乎公众号:智商前端特声明:原创不易,无未经授权转载或抄袭,如需转载,请联系作者授权。前言自上一篇技术文章《1.5万字概括ES6全部特性》发表以来,我已经4个月没有发表技术文章了。哈哈,不是不想写,是太忙了。这段时间每天不是上班就是加班,没有属于自己的时间。这篇文章也是业余时间完成的,希望大家喜欢,感谢大家一直以来对我的支持。reduce是ES5新增的常规数组方法之一。与forEach、filter、map相比,在实际使用中似乎被忽略了。发现身边的人很少用到,才导致这么厉害的方法逐渐被埋没。如果经常使用reduce,哪有这么好用的!还是要把他从尘土里拿出来擦干净,把它的高级用法呈现给大家。一个如此有效的方法不应该被群众埋没。下面简单介绍一下reduce的语法。具体可以参考MDN上关于reduce()的说明。定义:对数组中的每个元素执行一个自定义的累加器,并将结果汇??总成一个单一的返回值形式:array.reduce((t,v,i,a)=>{},initValue)参数回调:回调函数(required)initValue:回调函数的初始值(可选)参数total(t):累加器计算完成后的返回值(required)value(v):当前元素(required)index(i):当前元素的索引(可选)array(a):当前元素所属的数组对象(可选)该过程以t作为累加结果的初始值,如果不设置t,则从第一个开始遍历数组的元素作为初始值,使用累加器处理v,累加v到t的映射结果,结束本次循环,返回t进入下一次循环,重复上述操作,直到遍历完数组的最后一个元素,而返回finaltreduce的实质是将累加器Act对数组成员逐一转换,将上一次的输出值作为下一次的输入值。下面举个简单的栗子,看看reduce的计算结果。constarr=[3,5,1,4,2];consta=arr.reduce((t,v)=>t+v);//相当于constb=arr.reduce((t,v)=>t+v,0);看不懂代码也没关系,贴个reduce函数的动图应该就能看懂。reduce本质上是一个累加器函数,它使用用户自定义的累加器对数组成员进行自定义累加,得到累加器生成的一个值。另外,reduce还有一个弟弟,reduceRight。这两个方法的作用其实是一样的,只是reduce是升序执行,reduceRight是降序执行。在空数组上调用reduce()和reduceRight()将不会执行其回调函数。可以认为reduce()对于空数组是无效的。高级用法光是上面简单的栗子还不足以说明什么是reduce。为了展示reduce的魅力,我为大家提供了25个场景来应用reduce的高??级用法。一些高级用法可能需要结合其他方法来实现,这为reduce的多样化提供了更多的可能性。一些示例代码的编写可能有点棘手。如果你不习惯,你可以把它整理成你自己习惯的写作。累加和乘法函数Accumulation(...vals){returnvals.reduce((t,v)=>t+v,0);}functionMultiplication(...vals){returnvals.reduce((t,v)=>t*v,1);}累加(1,2,3,4,5);//15乘法(1,2,3,4,5);//120权重和constscores=[{score:90,subject:"chinese",weight:0.5},{score:95,subject:"math",weight:0.3},{score:85,subject:"english",权重:0.2}];constresult=scores.reduce((t,v)=>t+v.score*v.weight,0);//90.5相反reversefunctionReverse(arr=[]){returnarr.reduceRight((t,v)=>(t.push(v),t),[]);}Reverse([1,2,3,4,5]);//[5,4,3,2,1]而不是映射和过滤器constarr=[0,1,2,3];//而不是map:[0,2,4,6]consta=arr.map(v=>v*2);constb=arr.reduce((t,v)=>[...t,v*2],[]);//替换过滤器:[2,3]constc=arr.filter(v=>v>1);constd=arr.reduce((t,v)=>v>1?[...t,v]:t,[]);//替换地图和过滤器:[4,6]conste=arr.map(v=>v*2)。过滤器(v=>v>2);常量f=arr。reduce((t,v)=>v*2>2?[...t,v*2]:t,[]);而不是some和everyconstscores=[{score:45,subject:"chinese"},{score:90,subject:"math"},{score:60,subject:"english"}];//替换一些:至少一个合格的constisAtLeastOneQualified=scores.reduce((t,v)=>t||v.score>=60,false);//true//替换每个:所有符合条件的constisAllQualified=scores.reduce((t,v)=>t&&v.score>=60,true);//falsearraysplitfunctionChunk(arr=[],size=1){returnarr.length?arr.reduce((t,v)=>(t[t.length-1].length===size?t.push([v]):t[t.length-1].push(v),t),[[]]):[];}constarr=[1,2,3,4,5];块(arr,2);//[[1,2],[3,4],[5]]数组过滤函数Difference(arr=[],oarr=[]){returnarr.reduce((t,v)=>(!oarr.includes(v)&&t.push(v),t),[]);}constarr1=[1,2,3,4,5];constarr2=[2,3,6]差值(arr1,arr2);//[1,4,5]数组填充函数Fill(arr=[],val="",start=0,end=arr.length){if(start<0||start>=end||end>arr.length)returnarr;返回[...arr.slice(0,start),...arr.slice(start,end).reduce((t,v)=>(t.push(val||v),t),[]),...arr.slice(end,arr.length)];}constarr=[0,1,2,3,4,5,6];Fill(arr,"aaa",2,5);//[0,1,"aaa","aaa","aaa",5,6]数列函数Flat(arr=[]){returnarr.reduce((t,v)=>t.concat(Array.isArray(v)?Flat(v):v),[])}constarr=[0,1,[2,3],[4,5,[6,7]],[8,[9],10,[11,12]]]];平(arr);//[0,1,2,3,4,5,6,7,8,9,10,11,12]数去重函数Uniq(arr=[]){returnarr.reduce((t,v)=>t.includes(v)?t:[...t,v],[]);}constarr=[2,1,0,3,2,1,2];Uniq(arr);//[2,1,0,3]最大最小值函数Max(arr=[]){returnarr.reduce((t,v)=>t>v?t:v);}functionMin(arr=[]){returnarr.reduce((t,v)=>t(v.forEach((w,i)=>t[i].push(w)),t),Array.from({length:Math.max(...arr.map(v=>v.length))}).map(v=>[]));}constarr=[["a",1,true],["b",2,false]];解压(arr);//[["a","b"],[1,2],[true,false]]统计数组成员个数functionCount(arr=[]){returnarr.reduce((t,v)=>(t[v]=(t[v]||0)+1,t),{});}constarr=[0,1,1,2,2,2];计数(arr);//{0:1,1:2,2:3}这个方法就是字符统计和单词统计的原理。输入参数时,将字符串处理成数组,记录数组成员函数Position(arr=[],val){returnarr.reduce((t,v,i)=>(v===val&&t.push(i),t),[]);}constarr=[2,1,5,4,2,1,6,6,7];位置(arr,2);//[0,4]数组成员特征分组functionGroup(arr=[],key){returnkey?arr.reduce((t,v)=>(!t[v[key]]&&(t[v[key]]=[]),t[v[key]].push(v),t),{}):{};}constarr=[{地区:"GZ",姓名:"YZW",年龄:27},{地区:"GZ",姓名:"TYJ",年龄:25},{地区:"SZ",姓名:"AAA",年龄:23},{地区:"FS",姓名:"BBB",age:21},{area:"SZ",name:"CCC",age:19}];//按区域分组areaGroup(arr,"area");//{GZ:Array(2),SZ:Array(2),FS:Array(1)}统计数组成员包含的关键字functionKeyword(arr=[],keys=[]){returnkeys.reduce((t,v)=>(arr.some(w=>w.includes(v))&&t.push(v),t),[]);}consttext=["今天天气不错,我想去钓鱼”,“一边看电视,一边做作业”,“小明喜欢同桌的肖红,也喜欢后桌的肖军,他很委婉”,“最近有太多很多上班喜欢钓鱼的人,代码写得不好,做梦"];constkeyword=["懒","喜欢","睡觉","钓鱼","好","边","明天"];关键字(文本,关键字);//["like","fishing","good","oneside"]字符串反转函数ReverseStr(str=""){returnstr.split("").reduceRight((t,v)=>t+v);}conststr="减少是最好的";ReverseStr(str);//“reduceisthebestecuder”数字千差分functionThousandNum(num=0){conststr=(+num).toString().split(".");constint=nums=>nums.split("").reverse().reduceRight((t,v,i)=>t+(i%3?v:`${v},`),"").replace(/^,|,$/g,"");constdec=nums=>nums.split("").reduce((t,v,i)=>t+((i+1)%3?v:`${v},`),"").replace(/^,|,$/g,"");返回str.length>1?`${int(str[0])}.${dec(str[1])}`:int(str[0]);}ThousandNum(1234);//"1,234"ThousandNum(1234.00);//"1,234"千数(0.1234);//"0.123,4"ThousandNum(1234.5678);//"1,234.567,8"异步累加asyncfunctionAsyncTotal(arr=[]){returnarr.reduce(async(t,v)=>{constat=awaitt;consttodo=awaitTodo(v);at[v]=todo;返回;},Promise.resolve({}));}constresult=awaitAsyncTotal();//需要使用斐波那契数列functionFibonacci(len=2){constarr=[...newArray(len).keys()];returnarr.reduce((t,v,i)=>(i>1&&t.push(t[i-1]+t[i-2]),t),[0,1]);}斐波纳契(10);//[0,1,1,2,3,5,8,13,21,34]URL参数反序列化函数ParseUrlSearch(){returnlocation.search.replace(/(^\?)|(&$)/g,"").split("&").reduce((t,v)=>{const[key,val]=v.split("=");t[key]=decodeURIComponent(val);返回t;},{});}//假设网址为:https://www.baidu.com?age=25&name=TYJParseUrlSearch();//{age:"25",name:"TYJ"}URL参数序列化函数StringifyUrlSearch(search={}){returnObject.entries(search).reduce((t,v)=>`${t}${v[0]}=${encodeURIComponent(v[1])}&`,Object.keys(search).length?"?":"").replace(/&$/,"");}StringifyUrlSearch({年龄:27,姓名:"YZW"});//"?age=27&name=YZW"返回对象的指定key值functionGetKeys(obj={},keys=[]){returnObject.keys(obj).reduce((t,v)=>(keys.includes(v)&&(t[v]=obj[v]),t),{});}consttarget={a:1,b:2,c:3,d:4};const关键字=["a","d"];GetKeys(目标,关键字);//{a:1,d:4}arraytoobjectconstpeople=[{area:"GZ",name:"YZW",age:27},{area:"SZ",name:"TYJ",age:25}];const地图=人。减少((t,v)=>{常量{名字,...休息}=v;t[名字]=休息;返回t;},{});//{YZW:{...},TYJ:{...}}ReduxCompose函数原理functionCompose(...funs){if(funs.length===0){returnarg=>arg;}if(funs.length===1){returnfuns[0];返回乐趣。reduce((t,v)=>(...arg)=>t(v(...arg)));}兼容性和性能好用,但是兼容性呢?在Caniuse上搜索一下,兼容性绝对好,你可以在任何项目上大胆使用,不要吝啬你的想象力,充分发挥reduce的compose技能。对于时不时做一些累加的函数,reduce绝对是首选方法。另外,可能有同学会问,reduce的性能如何?下面我们通过同时对for、forEach、map、reduce这四个方法进行1到100000的累加操作,看看这四个方法各自的执行时间。//创建一个长度为100000的数组constlist=[...newArray(100000).keys()];//forconsole.time("for");letresult1=0;for(leti=0;i(result2+=v+1));console.log(result2);console.timeEnd("forEach");//mapconsole.time("map");letresult3=0;list.map(v=>(result3+=v+1,v));console.log(result3);console.timeEnd("map");//reduceconsole.time("reduce");constresult4=list.reduce((t,v)=>t+v+1,0);console.log(result4);console.timeEnd("reduce");累计运算执行时间为6.719970703125msforEach3.696044921875msmap3.554931640625msreduce2.806884765625ms以上代码在MacBookPro201915寸16G内存512G闪存Chrome79下执行,以上代码在不同机器不同环境下执行可能不同。我同时测试了多台机器和多个浏览器,连续执行了10多个操作,发现reduce整体平均执行时间还是略快于其他三种方式,大家可以放心使用!本文更多的是关于reduce的使用技巧。如果对reduce的兼容性和性能有疑问,可以参考相关资料进行验证。最后送你一张reduce生成的乘法口诀表:七取七,二七取四十八,3月8日妇女节,5月1日劳动节,6月1日儿童节。请点击此处了解代码详情。让我们发挥我们的想象力,训练我们的大脑思维。更多JS秀操作请查看我的文章《灵活运用JS开发技巧》。结语??关注+点赞+收藏+评论+转发??,原创不易,鼓励作者创作更多优质文章关注公众号IQ前端,一个专注于CSS/JS开发技巧的前端公众号,更多前端小技巧干货等着你。关注并回复即可免费领取学习资料。关注和回复群拉你进技术交流群。欢迎关注智商前端。更多CSS/JS开发技巧只会推送在公众号