安庆大理运城常德铜陵江西
投稿投诉
江西南阳
嘉兴昆明
铜陵滨州
广东西昌
常德梅州
兰州阳江
运城金华
广西萍乡
大理重庆
诸暨泉州
安庆南充
武汉辽宁

JavaScript数组高性能去重解决方案

11月7日 温柔冢投稿
  在大多数的人眼里,数组去重是一个很简单的课题,很多人甚至熟练掌握了多种数组去重的方法,然而大多时候,我们却忽略了数组去重所消耗的时间资源。譬如我们在做前端性能优化的时候,又有多少人会考虑JavaScript的运行性能。今天,我将通过一组测试数据来给大家展示高性能数组去重的必要性。当然以上仅针对像我这样的强迫症患者,。
  先展示下结论,有些不喜欢看过程的同学可以直接拿去用,当然你也可以使用本人的高性能js工具集:npmiefficientjs最高性能数组去重方法10万数量级:3毫秒,100万数量级:6毫秒,1000万数量级36毫秒Array。prototype。distinctfunction(){varhash〔〕;varobj{};for(i0;this〔i〕!i){if(!obj〔this〔i〕〕){hash。push(this〔i〕);obj〔this〔i〕〕this〔i〕;}}}
  一、收集数组去重的方法
  1、遍历数组法:实现思路:新建一个数组,遍历去要重的数组,当值不在新数组的时候(indexOf为1)就加入该新数组中;
  2、数组下标判断法:实现思路:如果当前数组的第i项在当前数组中第一次出现的位置不是i,那么表示第i项是重复的,忽略掉。否则存入结果数组。
  3、排序后相邻去除法:实现思路:给传入的数组排序,排序后相同的值会相邻,然后遍历排序后数组时,新数组只加入不与前一值重复的值。
  4、优化遍历数组法(推荐):实现思路:双层循环,外循环表示从0到arr。length,内循环表示从i1到arr。length,将没重复的右边值放入新数组。(检测到有重复值时终止当前循环同时进入外层循环的下一轮判断)
  5、ES6实现:
  a、实现思路:ES6提供了新的数据结构Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。Set函数可以接受一个数组(或类似数组的对象)作为参数,用来初始化。
  b、实现思路:Array。filter()indexOf
  6、双重for循环(最容易理解):实现思路:外层循环遍历元素,内层循环检查是否重复,当有重复值的时候,可以使用push(),也可以使用splice()
  7、for。。。ofincludes()(双重for循环的升级版):实现思路:外层用for。。。of语句替换for循环,把内层循环改为includes(),先创建一个空数组,当includes()返回false的时候,就将该元素push到空数组中,类似的,还可以用indexOf()来替代includes()
  8、Array。sort():实现思路:首先使用sort()将数组进行排序,然后比较相邻元素是否相等,从而排除重复项
  9、for。。。ofObject:实现思路:利用Object唯一key的特性来实现去重
  以上的方法去重都没问题,都可以实现数组去重的目的,但是性能差距很大,可能处理10000条数据以内的表现不回太明显,但是无论哪个程序都是由很多很多的指令组成的,假如你不去关注每一条指令的优化,而想当然的想直接优化程序,那么你注定会失败。毋以善小而不为,虽然用在这里有些欠妥,但大体就是这个意思,一切都要从细节入手。我们先看看上面的去重方法,方法很多,我们需理一下,虽然上面的方法看起来思路不一样,但是可以分为两类:遍历数组和直接使用内置方法
  然而遍历数组的方式有很多种,甚至不止上面的这些方法,我们首先对比遍历数组的方法的效率,然后在对比其他的
  二、建立多维度的测试模板并验证
  以下是测试结果的环境
  首先我们列出所有的遍历数组的方法functiongetRandomIntInclusive(min,max){minMath。ceil(min);maxMath。floor(max);returnMath。floor(Math。random()(maxmin1))Themaximumisinclusiveandtheminimumisinclusive}varorgArrayArray。from(newArray(100000),(){returngetRandomIntInclusive(1,1000);})普通for循环Array。prototype。distinct1function(){varhash〔〕;for(i0;ithis。i){if(hash。indexOf(this〔i〕)1){hash。push(this〔i〕);}}}优化版for循环Array。prototype。distinct2function(){varhash〔〕;for(i0,lenthis。i){if(hash。indexOf(this〔i〕)1){hash。push(this〔i〕);}}}弱化版for循环Array。prototype。distinct3function(){varhash〔〕;for(i0;this〔i〕!i){if(hash。indexOf(this〔i〕)1){hash。push(this〔i〕);}}}foreachArray。prototype。distinct4function(){varhash〔〕;this。forEach(item{if(hash。indexOf(item)1){hash。push(item);}})}foreach变种Array。prototype。distinct5function(){varhash〔〕;Array。prototype。forEach。call(this,item{if(hash。indexOf(item)1){hash。push(item);}})}forinArray。prototype。distinct6function(){varhash〔〕;for(keyinthis){varitemthis〔key〕if(hash。indexOf(item)1){hash。push(item);}}}mapArray。prototype。distinct7function(){varhash〔〕;this。map(item{if(hash。indexOf(item)1){hash。push(item);}});}forofArray。prototype。distinct8function(){varhash〔〕;for(letitemofthis){if(hash。indexOf(item)1){hash。push(item);}}}varstartTime,endTime,functiontest(types){types。forEach(type{startTimenewDate();rtnorgArray〔type〕();endTimenewDate();console。log(数量级〔{orgArray。length10000}万〕去重后数组长度为{rtn。length},使用{type}消耗时长{endTimestartTime}毫秒)console。log();})}vartestArray〔〕;for(i1;i8;i){testArray。push(distincti);}test(testArray)
  输出结果:
  把数据量级提高到100万、1000万,测试结果如下:
  基于以上测试结果我们可以排除forin,但是其他的遍历数组的方法相差不到,我们取目前表现最好的弱化版for循环(其实针对我们的测试环境是强化版,哈哈)
  (distinct6的去重后结果居然是1008,这个其实个forin的遍历机制有关,forin会遍历其原型链,所以forin不适合遍历数组,具体参考forin和forof的区别)
  上代码functiongetRandomIntInclusive(min,max){minMath。ceil(min);maxMath。floor(max);returnMath。floor(Math。random()(maxmin1))Themaximumisinclusiveandtheminimumisinclusive}varorgArrayArray。from(newArray(100000),(){returngetRandomIntInclusive(1,1000);})indexOfArray。prototype。distinct1function(){varhash〔〕;for(i0;this〔i〕!i){if(hash。indexOf(this〔i〕)1){hash。push(this〔i〕);}}}数组下标判断法Array。prototype。distinct2function(){varhash〔〕;for(i0;this〔i〕!i){if(this。indexOf(this〔i〕)i){hash。push(this〔i〕);}}}includesArray。prototype。distinct3function(){varhash〔〕;for(i0;this〔i〕!i){if(!hash。includes(this〔i〕)){hash。push(this〔i〕);}}}ObjectArray。prototype。distinct4function(){varhash〔〕;varobj{};for(i0;this〔i〕!i){if(!obj〔i〕){hash。push(this〔i〕);obj〔i〕this〔i〕;}}}varstartTime,endTime,functiontest(types){types。forEach(type{startTimenewDate();rtnorgArray〔type〕();endTimenewDate();console。log(数量级〔{orgArray。length10000}万〕去重后数组长度为{rtn。length},使用{type}消耗时长{endTimestartTime}毫秒)console。log();})}vartestArray〔〕;for(i1;i4;i){testArray。push(distincti);}test(testArray)
  测试结果如下
  这个结果就拉开差距了,在看下100万和1000万的结果
  结论很明确,数据量级呈线性增长,正常的遍历数组的方式中中用objec的方法效率大大领先其他方法,我们再次来回顾下object方法的实现思路,
  利用Object唯一key的特性来实现去重
  为了保证不漏掉,我们object的去重取执行所有的遍历方法functiongetRandomIntInclusive(min,max){minMath。ceil(min);maxMath。floor(max);returnMath。floor(Math。random()(maxmin1))Themaximumisinclusiveandtheminimumisinclusive}varorgArrayArray。from(newArray(100000),(){returngetRandomIntInclusive(1,1000);})普通for循环Array。prototype。distinct1function(){varhash〔〕;varobj{};for(i0;ithis。i){if(!obj〔this〔i〕〕){hash。push(this〔i〕);obj〔this〔i〕〕this〔i〕;}}}优化版for循环Array。prototype。distinct2function(){varhash〔〕;varobj{};for(i0,lenthis。i){if(!obj〔this〔i〕〕){hash。push(this〔i〕);obj〔this〔i〕〕this〔i〕;}}}弱化版for循环Array。prototype。distinct3function(){varhash〔〕;varobj{};for(i0;this〔i〕!i){if(!obj〔this〔i〕〕){hash。push(this〔i〕);obj〔this〔i〕〕this〔i〕;}}}foreachArray。prototype。distinct4function(){varhash〔〕;varobj{};this。forEach(item{if(!obj〔item〕){hash。push(item);obj〔item〕}})}foreach变种Array。prototype。distinct5function(){varhash〔〕;varobj{};Array。prototype。forEach。call(this,item{if(!obj〔item〕){hash。push(item);obj〔item〕}})}forinArray。prototype。distinct6function(){varhash〔〕;varobj{};for(keyinthis){varitemthis〔key〕;if(!obj〔item〕){hash。push(item);obj〔item〕}}}mapArray。prototype。distinct7function(){varhash〔〕;varobj{};this。map(item{if(!obj〔item〕){hash。push(item);obj〔item〕}});}forofArray。prototype。distinct8function(){varhash〔〕;varobj{};for(letitemofthis){if(!obj〔item〕){hash。push(item);obj〔item〕}}}varstartTime,endTime,functiontest(types){types。forEach(type{startTimenewDate();rtnorgArray〔type〕();endTimenewDate();console。log(数量级〔{orgArray。length10000}万〕去重后数组长度为{rtn。length},使用{type}消耗时长{endTimestartTime}毫秒)console。log();})}vartestArray〔〕;for(i1;i8;i){testArray。push(distincti);}test(testArray)
  结论如下
  依然再次测试100万和1000万的,结果如下
  可以得出结论,普通的for循环(优化版、弱化版)加上Object的组合在遍历数组的方法大幅领先其他方法,我们现在可以使用object与其他方法进行对比来
  (distinct6的去重后结果居然是1008,这个其实个forin的遍历机制有关,forin会遍历其原型链,所以forin不适合遍历数组,具体参考forin和forof的区别)functiongetRandomIntInclusive(min,max){minMath。ceil(min);maxMath。floor(max);returnMath。floor(Math。random()(maxmin1))Themaximumisinclusiveandtheminimumisinclusive}varorgArrayArray。from(newArray(100000),(){returngetRandomIntInclusive(1,1000);})普通for循环Array。prototype。distinct1function(){varhash〔〕;varobj{};for(i0;ithis。i){if(!obj〔this〔i〕〕){hash。push(this〔i〕);obj〔this〔i〕〕this〔i〕;}}}优化版for循环Array。prototype。distinct2function(){varhash〔〕;varobj{};for(i0,lenthis。i){if(!obj〔this〔i〕〕){hash。push(this〔i〕);obj〔this〔i〕〕this〔i〕;}}}弱化版for循环Array。prototype。distinct3function(){varhash〔〕;varobj{};for(i0;this〔i〕!i){if(!obj〔this〔i〕〕){hash。push(this〔i〕);obj〔this〔i〕〕this〔i〕;}}}newSet()〔。。。〕Array。prototype。distinct4function(){return〔。。。newSet(this)〕;}newSet()Array。fromArray。prototype。distinct5function(){returnArray。from(newSet(this));}Array。filter()ObjectArray。prototype。distinct6function(){varhash〔〕;varobj{};returnthis。filter(item{if(!obj〔item〕){obj〔item〕}})}双重for循环Array。prototype。distinct7function(){letarr〔。。。this〕;for(leti0,lenarr。i){for(letji1;j){if(arr〔i〕arr〔j〕){arr。splice(j,1);splice会改变数组长度,所以要将数组长度len和下标j减一j;}}}returnarr}Array。sort()Array。prototype。distinct8function(){vararrthis。sort()letresult〔arr〔0〕〕for(leti1,lenarr。i){arr〔i〕!arr〔i1〕result。push(arr〔i〕)}returnresult}varstartTime,endTime,functiontest(types){types。forEach(type{startTimenewDate();rtnorgArray〔type〕();endTimenewDate();console。log(数量级〔{orgArray。length10000}万〕去重后数组长度为{rtn。length},使用{type}消耗时长{endTimestartTime}毫秒)console。log();})}vartestArray〔〕;for(i1;i8;i){testArray。push(distincti);}test(testArray)
  结果如下
  基本上可以去除双重for循环和Array。sort(),我们再次测试100万数量级别的
  双重for循环执行挂掉了看下30万的
  我们去除双重for循环执行100万和1000万
  很明显普通for循环(包含优化版和弱化版)Object遥遥领先。
  三、给出测试结果报告
  通过多次执行普通for循环、优化版、弱化版,最终得出结论,效率:弱化版普通版优化版
  弱化版可以更名特殊版,哈哈
  最高性能数组去重方法10万数量级:3毫秒,100万数量级:6毫秒,1000万数量级36毫秒Array。prototype。distinctfunction(){varhash〔〕;varobj{};for(i0;this〔i〕!i){if(!obj〔this〔i〕〕){hash。push(this〔i〕);obj〔this〔i〕〕this〔i〕;}}}
投诉 评论 转载

世界上最邪恶的公司孟山都,毒害数百万人,其产品在我国仍有存留英国专家在新冠病毒的基因当中,发现其中有美国公司莫德纳,在2016年2月申请的专利基因片段。美国科学家坐不住了,立马跳出来辩解:这纯属巧合,大家不要慌。你总不能因为你家的孩子跟……库里终得圆满,威少是湖人最佳球员?首次发布于公众号:篮球老友记终得圆满!库里本科毕业!2022年9月1日,戴维森学院为库里颁发了本科毕业证书,并退役了他的球衣。库里的大学教练BobMcKillop在接受记……32!沈梦雨小角度爆射破网,收获留洋第2冠,女足新星太给力了北京时间5月29日晚23时10分,20212022赛季苏格兰女子足总杯决赛,10人凯尔特人女足通过加时32击败格拉斯哥城队捧杯,凯尔特人女足加冕双冠王,中国女足新星沈梦雨本场比……韩国足协正式申办2023年男足亚洲杯文羊城晚报全媒体记者刘毅韩国足协9月15日宣布,已经正式向亚足联提交举办2023年男足亚洲杯的申请。亚足联将于10月17日在马来西亚吉隆坡举行执委会决定主办国,卡塔尔和印……酒店如何实现智慧化升级?九号公司旗下九号机器人给出答案酒店行业作为传统行业,随着智能化时代的到来,它也借助科技手段对用户的入住、餐饮、订房等全方面进行赋能,提升效率和服务质量,对酒店进行智慧化升级其实已经成为酒店行业寻求降本提效的……以前的伴生皮有模有样,现在的伴生皮一模一样说起伴生皮,应该有不少老玩家有话要说吧,其实最开始的王者荣耀伴生皮,每一款都是非常良心的,从建模到特效,都完美的展现了皮肤的主题,而现在嘛。。。。。今天我们就一起来看看,王者荣……JavaScript数组高性能去重解决方案在大多数的人眼里,数组去重是一个很简单的课题,很多人甚至熟练掌握了多种数组去重的方法,然而大多时候,我们却忽略了数组去重所消耗的时间资源。譬如我们在做前端性能优化的时候,又有多……国庆期间做完这些热门项目,还能出去玩吗?盼星星,盼月亮,大家终于盼来七天的大长假,很多人都会趁着这个大假期做些医美项目,毕竟国庆有优惠活动,天气也凉爽些,做完后就可以直接躺平等恢复了。当然,也有想做医美又外出游……9月仅卖出260辆,为啥优惠4万块,电动版宝马3系照样卖不动随着新能源的发展,市场慢慢地从燃油车向电动车转变。作为电动化时代下的标杆车型,特斯拉Model3以不太高的入门售价,出色的科技性能,以及不错的驾控体验,深受当代年轻消费者的喜爱……故事自驾游时与穷游女一段情缘自由散漫的性格,让我厌倦了大城市的生活节奏,随着谈了五年的女朋友离开,我决定辞职,开着房车来次说走就走的旅游。这天,我到太湖已是傍晚,下车后看到看到一个女人在玩滑板,我走……A股中国移动的大股东是谁?中国移动的大股东是谁?中国移动的全称是,中国移动有限公司;大股东,中国移动香港(BVI)有限公司;行业类别,通信运营,信息传输、软件和信息技术服务业,电信、广播电视和卫星……CBA常规赛首轮!张镇麟缺阵,广东队不战而败,马布里最开心北京时间10月10日,202223赛季CBA常规赛将正式打响,联赛首轮,自然会有不少的看点,CBA也想着打出一个开门红,让更多的人来关注中国男子篮球职业联赛。揭幕战,CBA安排……
友谊万岁丨神仙友情的宝藏文案子弹为什么不能朝天空射击?15年前教训太过惨痛,各国才明令禁曝广州队或裁掉林书豪!郭士强也救不了他,就此告别CBA恭喜中国女排,郎平2位爱徒赴任新岗位,球迷欢呼支持继北慕之后,可杰低调上分冲到巅峰第一,轻松冲上2000分只建不用,新能源充电桩被疑骗补造假?再有患者追问,我都会把这篇文章,直接当医嘱发给他泰国2022年芭提雅比基尼沙滩赛跑10月29日正式举行ampampquot豪门阔太ampampquot王艳嫁二婚富要性价比,更要强续航!2022年四款优秀的智能手机,向您诚恳乒乓男皇王励勤错过真爱,娶小10岁娇妻生子,日子过得有滋有味马特乌斯选德国世界杯26人名单诺伊尔穆勒领衔,罗伊斯未入选

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找七猫云易事利