范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

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

  在大多数的人眼里,数组去重是一个很简单的课题,很多人甚至熟练掌握了多种数组去重的方法,然而大多时候,我们却忽略了数组去重所消耗的时间资源。譬如我们在做前端性能优化的时候,又有多少人会考虑JavaScript的运行性能。今天,我将通过一组测试数据来给大家展示高性能数组去重的必要性。当然以上仅针对像我这样的强迫症患者,。
  先展示下结论,有些不喜欢看过程的同学可以直接拿去用,当然你也可以使用本人的高性能js工具集:npm i efficient-js // 最高性能数组去重方法 10万数量级:3毫秒,100万数量级:6毫秒,1000万数量级36毫秒 Array.prototype.distinct = function () {   var hash=[];   var obj = {};   for (i = 0; this[i] != null; i++) {     if(!obj[this[i]]){       hash.push(this[i]);       obj[this[i]] = this[i];     }   }   return hash; }
  一、收集数组去重的方法
  1、遍历数组法: 实现思路:新建一个数组,遍历去要重的数组,当值不在新数组的时候(indexOf为-1)就加入该新数组中;
  2、数组下标判断法: 实现思路:如果当前数组的第 i 项在当前数组中第一次出现的位置不是 i,那么表示第 i 项是重复的,忽略掉。否则存入结果数组。
  3、排序后相邻去除法: 实现思路:给传入的数组排序,排序后相同的值会相邻,然后遍历排序后数组时,新数组只加入不与前一值重复的值。
  4、优化遍历数组法(推荐): 实现思路:双层循环,外循环表示从0到arr.length,内循环表示从i+1到arr.length,将没重复的右边值放入新数组。(检测到有重复值时终止当前循环同时进入外层循环的下一轮判断)
  5、ES6实现:
  a、实现思路:ES6提供了新的数据结构Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。Set函数可以接受一个数组(或类似数组的对象)作为参数,用来初始化。
  b、实现思路:Array.filter() + indexOf
  6、双重 for 循环(最容易理解): 实现思路:外层循环遍历元素,内层循环检查是否重复,当有重复值的时候,可以使用 push(),也可以使用 splice()
  7、for...of + includes() (双重for循环的升级版): 实现思路:外层用 for...of 语句替换 for 循环,把内层循环改为 includes(),先创建一个空数组,当 includes() 返回 false 的时候,就将该元素 push 到空数组中 ,类似的,还可以用 indexOf() 来替代 includes()
  8、Array.sort(): 实现思路:首先使用 sort() 将数组进行排序,然后比较相邻元素是否相等,从而排除重复项
  9、for...of + Object:  实现思路:利用Object唯一key的特性来实现去重
  以上的方法去重都没问题,都可以实现数组去重的目的,但是性能差距很大,可能处理10000条数据以内的表现不回太明显,但是无论哪个程序都是由很多很多的指令组成的,假如你不去关注每一条指令的优化,而想当然的想直接优化程序,那么你注定会失败。"毋以善小而不为",虽然用在这里有些欠妥,但大体就是这个意思,一切都要从细节入手。我们先看看上面的去重方法,方法很多,我们需理一下,虽然上面的方法看起来思路不一样,但是可以分为两类:遍历数组和直接使用内置方法
  然而遍历数组的方式有很多种,甚至不止上面的这些方法,我们首先对比遍历数组的方法的效率,然后在对比其他的
  二、建立多维度的测试模板并验证
  以下是测试结果的环境
  首先我们列出所有的遍历数组的方法 function getRandomIntInclusive(min, max) {   min = Math.ceil(min);   max = Math.floor(max);   return Math.floor(Math.random() * (max - min + 1)) + min; //The maximum is inclusive and the minimum is inclusive  } var orgArray = Array.from(new Array(100000), ()=>{     return getRandomIntInclusive(1, 1000); })  // 普通for循环 Array.prototype.distinct1 = function () {   var hash=[];   for (i = 0; i < this.length; i++) {      if(hash.indexOf(this[i])==-1){       hash.push(this[i]);      }   }   return hash; } // 优化版for循环 Array.prototype.distinct2 = function () {   var hash=[];   for (i = 0, len = this.length; i < len; i++) {      if(hash.indexOf(this[i])==-1){       hash.push(this[i]);      }   }   return hash; } // 弱化版for循环 Array.prototype.distinct3 = function () {   var hash=[];   for (i = 0; this[i] != null; i++) {      if(hash.indexOf(this[i])==-1){       hash.push(this[i]);      }   }   return hash; } // foreach Array.prototype.distinct4 = function () {   var hash=[];   this.forEach(item => {     if(hash.indexOf(item)==-1){       hash.push(item);      }   })   return hash; } // foreach变种 Array.prototype.distinct5 = function () {   var hash=[];   Array.prototype.forEach.call(this, item => {     if(hash.indexOf(item)==-1){       hash.push(item);      }   })   return hash; } // forin Array.prototype.distinct6 = function () {   var hash=[];   for (key in this) {    var item = this[key]      if(hash.indexOf(item)==-1){       hash.push(item);      }   }   return hash; } // map Array.prototype.distinct7 = function () {   var hash=[];   this.map(item => {      if(hash.indexOf(item)==-1){       hash.push(item);      }   });   return hash; } // forof Array.prototype.distinct8 = function () {   var hash=[];   for (let item of this) {      if(hash.indexOf(item)==-1){       hash.push(item);      }   }   return hash; } var startTime,endTime, rtn; function test(types) {   types.forEach(type => {     startTime = new Date();     rtn = orgArray[type]();     endTime = new Date();     console.log(`数量级[${orgArray.length/10000}万]去重后数组长度为${rtn.length},使用${type}消耗时长${endTime - startTime}毫秒`)     console.log("----------------------------------------------------------------------");   }) } var testArray = []; for (i = 1; i <= 8;i++) {   testArray.push("distinct" + i); } test(testArray)
  输出结果:
  把数据量级提高到100万、1000万,测试结果如下:
  基于以上测试结果我们可以排除forin,但是其他的遍历数组的方法相差不到,我们取目前表现最好的弱化版for循环(其实针对我们的测试环境是强化版,哈哈)
  (distinct6的去重后结果居然是1008,这个其实个for in的遍历机制有关,for in会遍历其原型链,所以for in不适合遍历数组,具体参考forin和forof的区别)
   上代码 function getRandomIntInclusive(min, max) {   min = Math.ceil(min);   max = Math.floor(max);   return Math.floor(Math.random() * (max - min + 1)) + min; //The maximum is inclusive and the minimum is inclusive  } var orgArray = Array.from(new Array(100000), ()=>{     return getRandomIntInclusive(1, 1000); })   // indexOf Array.prototype.distinct1 = function () {   var hash=[];   for (i = 0; this[i] != null; i++) {      if(hash.indexOf(this[i])==-1){       hash.push(this[i]);      }   }   return hash; }  // 数组下标判断法 Array.prototype.distinct2 = function () {   var hash=[];   for (i = 0; this[i] != null; i++) {      if(this.indexOf(this[i])==i){       hash.push(this[i]);      }   }   return hash; }  // includes Array.prototype.distinct3 = function () {   var hash=[];   for (i = 0; this[i] != null; i++) {      if(!hash.includes(this[i])){       hash.push(this[i]);      }   }   return hash; }  // Object Array.prototype.distinct4 = function () {   var hash=[];   var obj = {};   for (i = 0; this[i] != null; i++) {      if(!obj[i]){       hash.push(this[i]);       obj[i] = this[i];      }   }   return hash; }  var startTime,endTime, rtn; function test(types) {   types.forEach(type => {     startTime = new Date();     rtn = orgArray[type]();     endTime = new Date();     console.log(`数量级[${orgArray.length/10000}万]去重后数组长度为${rtn.length},使用${type}消耗时长${endTime - startTime}毫秒`)     console.log("----------------------------------------------------------------------");   }) } var testArray = []; for (i = 1; i <= 4;i++) {   testArray.push("distinct" + i); } test(testArray)
  测试结果如下
  这个结果就拉开差距了,在看下100万和1000万的结果
  结论很明确,数据量级呈线性增长,正常的遍历数组的方式中中用objec的方法效率大大领先其他方法,我们再次来回顾下object方法的实现思路,
   利用Object唯一key的特性来实现去重 
  为了保证不漏掉,我们object的去重取执行所有的遍历方法 function getRandomIntInclusive(min, max) {   min = Math.ceil(min);   max = Math.floor(max);   return Math.floor(Math.random() * (max - min + 1)) + min; //The maximum is inclusive and the minimum is inclusive  } var orgArray = Array.from(new Array(100000), ()=>{     return getRandomIntInclusive(1, 1000); })  // 普通for循环 Array.prototype.distinct1 = function () {   var hash=[];   var obj = {};   for (i = 0; i < this.length; i++) {     if(!obj[this[i]]){       hash.push(this[i]);       obj[this[i]] = this[i];     }   }   return hash; } // 优化版for循环 Array.prototype.distinct2 = function () {   var hash=[];   var obj = {};   for (i = 0, len = this.length; i < len; i++) {     if(!obj[this[i]]){       hash.push(this[i]);       obj[this[i]] = this[i];     }   }   return hash; } // 弱化版for循环 Array.prototype.distinct3 = function () {   var hash=[];   var obj = {};   for (i = 0; this[i] != null; i++) {     if(!obj[this[i]]){       hash.push(this[i]);       obj[this[i]] = this[i];     }   }   return hash; } // foreach Array.prototype.distinct4 = function () {   var hash=[];   var obj = {};   this.forEach(item => {     if(!obj[item]){       hash.push(item);       obj[item] = item;     }   })   return hash; } // foreach变种 Array.prototype.distinct5 = function () {   var hash=[];   var obj = {};   Array.prototype.forEach.call(this, item => {     if(!obj[item]){       hash.push(item);       obj[item] = item;     }   })   return hash; } // forin Array.prototype.distinct6 = function () {   var hash=[];   var obj = {};   for (key in this) {   var item = this[key];     if(!obj[item]){       hash.push(item);       obj[item] = item;     }   }   return hash; } // map Array.prototype.distinct7 = function () {   var hash=[];   var obj = {};   this.map(item => {     if(!obj[item]){       hash.push(item);       obj[item] = item;     }   });   return hash; } // forof Array.prototype.distinct8 = function () {   var hash=[];   var obj = {};   for (let item of this) {     if(!obj[item]){       hash.push(item);       obj[item] = item;     }   }   return hash; } var startTime,endTime, rtn; function test(types) {   types.forEach(type => {     startTime = new Date();     rtn = orgArray[type]();     endTime = new Date();     console.log(`数量级[${orgArray.length/10000}万]去重后数组长度为${rtn.length},使用${type}消耗时长${endTime - startTime}毫秒`)     console.log("----------------------------------------------------------------------");   }) } var testArray = []; for (i = 1; i <= 8;i++) {   testArray.push("distinct" + i); } test(testArray)
  结论如下
  依然再次测试100万和1000万的,结果如下
  可以得出结论,普通的for循环(优化版、弱化版)加上Object的组合在遍历数组的方法大幅领先其他方法,我们现在可以使用object与其他方法进行对比来
   (distinct6的去重后结果居然是1008,这个其实个for in的遍历机制有关,for in会遍历其原型链,所以for in不适合遍历数组,具体参考 forin和forof的区别 )function getRandomIntInclusive(min, max) {   min = Math.ceil(min);   max = Math.floor(max);   return Math.floor(Math.random() * (max - min + 1)) + min; //The maximum is inclusive and the minimum is inclusive  } var orgArray = Array.from(new Array(100000), ()=>{     return getRandomIntInclusive(1, 1000); })  // 普通for循环 Array.prototype.distinct1 = function () {   var hash=[];   var obj = {};   for (i = 0; i < this.length; i++) {     if(!obj[this[i]]){       hash.push(this[i]);       obj[this[i]] = this[i];     }   }   return hash; } // 优化版for循环 Array.prototype.distinct2 = function () {   var hash=[];   var obj = {};   for (i = 0, len = this.length; i < len; i++) {     if(!obj[this[i]]){       hash.push(this[i]);       obj[this[i]] = this[i];     }   }   return hash; } // 弱化版for循环 Array.prototype.distinct3 = function () {   var hash=[];   var obj = {};   for (i = 0; this[i] != null; i++) {     if(!obj[this[i]]){       hash.push(this[i]);       obj[this[i]] = this[i];     }   }   return hash; } // new Set() + [...] Array.prototype.distinct4 = function () {   return [...new Set(this)]; } // new Set() + Array.from Array.prototype.distinct5 = function () {   return Array.from(new Set(this)); } // Array.filter() + Object Array.prototype.distinct6 = function () {   var hash=[];   var obj = {};   return this.filter(item => {     if (!obj[item]) {       obj[item] = item;       return true;     }   }) } // 双重for循环 Array.prototype.distinct7 = function () {   let arr = [...this];   for (let i=0, len=arr.length; i {     startTime = new Date();     rtn = orgArray[type]();     endTime = new Date();     console.log(`数量级[${orgArray.length/10000}万]去重后数组长度为${rtn.length},使用${type}消耗时长${endTime - startTime}毫秒`)     console.log("----------------------------------------------------------------------");   }) } var testArray = []; for (i = 1; i <= 8;i++) {   testArray.push("distinct" + i); } test(testArray)
  结果如下
  基本上可以去除双重for循环和Array.sort(),我们再次测试100万数量级别的
  双重for循环执行挂掉了…看下30万的
  我们去除双重for循环执行100万和1000万
  很明显普通for循环(包含优化版和弱化版)+ Object遥遥领先。
  三、给出测试结果报告
   通过多次执行普通for循环、优化版、弱化版,最终得出结论,效率:弱化版>普通版>优化版
  弱化版可以更名特殊版,哈哈
  // 最高性能数组去重方法 10万数量级:3毫秒,100万数量级:6毫秒,1000万数量级36毫秒 Array.prototype.distinct = function () {   var hash=[];   var obj = {};   for (i = 0; this[i] != null; i++) {     if(!obj[this[i]]){       hash.push(this[i]);       obj[this[i]] = this[i];     }   }   return hash; }

霍格沃茨之遗领衔,2023次时代大作扎堆!不用PS5也能畅玩2023年可谓是次时代游戏大年,刚刚开年就有大批新作上市,让无数玩家翘首期盼。其中最热门的当属刚刚上市开售的霍格沃茨之遗,作为哈利波特IP衍生作品,已经达成Steam周销榜的三连霸永恒岛之彩虹回忆60法师转职攻略哈喽,小编今天来为大家介绍60级法师转职攻略法师的转职有魔法师吉他手个人推荐吉他手法师可以转吉他手和魔法师。魔法师一般都是远攻。不过血防攻都很低。唯一高的就是法了。不过后期也很强。误将爱情动作片传给了女同事,我该怎么办最近小弟遇到一件郁闷事,现在想起就想说出来一吐为快,也请大家出谋划策。进入正题大学毕业后来到单位上班,由于工作比较枯燥,且背井离乡,我平时的娱乐就以打打魔兽为主,不是网游。后来单位幻塔白月魁持续伤害流玩法解析白月魁武器搭配推荐幻塔白月魁在连持续伤害流的武器搭配上推荐双枪红莲刀冰弓白月魁,这套的武器搭配思路是双枪高频率输出搭配上任意充能武器,够让双枪电能光束不再落空。幻塔白月魁持续伤害流玩法解析白月魁武器被上海街头的阿姨奶奶们惊艳了!穿衣比90后还潮,真养眼近两年非常热门的阿姨奶奶们的穿搭真的是能够直接凸显出来惊艳和冲上热门的程度,尤其是上海街头的街拍穿搭能够吸引眼球的也是各位中年女性或者老年女性的搭配呈现。她们的穿衣搭配真的是要比9儿童咳嗽,病因大不同!分清干咳痰咳晨咳夜咳,久咳不止!春季和开学后的这几天,问诊量激增,尤其是咳嗽的孩子最多。有些孩子是早上起床咳,有些则是晚饭时咳,还有一些在白天没太多表现,但晚上躺下就咳嗽不断,甚至咳嗽的时候喘不上气,闷咳。还有些手机辐射对儿童健康的影响在哪里?儿童不仅仅是小大人。他们不断成长的身体与认知使他们特别容易受到周围环境的影响,包括手机辐射。由于儿童接触这些新技术越来越早,因此调查手机使用是否对健康有害愈发重要。到底什么是手机辐春天里,这种儿童疾病高发,但家长还不重视,该注意什么?现在春季,儿童过敏性鼻炎比较好发,有些家长认为儿童过敏性鼻炎是一种无关紧要的疾病有些家长在孩子有症状时候使用药物,症状好转就停药,要么不重视,要么存在误区。在以前大多数认为它只是鼻打造通往元宇宙的关键钥匙上海临港布局XR产业新赛道图为当日会议现场。上海自贸区临港新片区官方供图中新网上海2月21日电(记者李姝徵)打造通往元宇宙的关键钥匙,中国(上海)自由贸易试验区临港新片区(以下简称临港新片区)正加速布局XR训练场上小妙招!火箭军某部五小活动激发备战热情春风浩荡,战鼓声急练兵备战,恰逢其时连日来,火箭军某部高起点高状态开展新年度军事训练工作树立大抓练兵备战鲜明导向灵活运用五小载体活动全面掀起军事训练热潮小培训夯实训练根基遴选专业技数字仓鼠需要断舍离吗?特评文丨深圳特区报评论员尹传刚置身数字化的信息空间,有些人成了爱囤积数据的数字仓鼠。他们像小仓鼠一样,将大量图片文档视频等数据信息囤积起来。在网络上,我们可以轻易找到数字仓鼠们的自道当
你们知道吗?其实在元朝和明朝之间,还有一个朝代大夏朝文墨客史说编辑墨客史说前言元末明初时期,因为元朝的横征暴敛,以及不注重民生,加之天灾人祸后。帝国的统治秩序,光靠武力维持已经难以为继。此时中华大地,汉人开始揭竿而起,冲击着元帝国的为什么邓肯的历史地位低于詹姆斯这个结论看起来矛盾吗?一点也不。因为詹姆斯粉丝要想抬高他的历史地位,邓肯不仅是挡在前面的一座大山,而且邓肯的生涯履历特别克老詹,经常扒老詹底裤。其实老詹抱团不需要找乱七八糟德理由,性感女神梦露被美国总统肯尼迪兄弟两人占有,36岁裸死在床上1962年8月5日清晨时分,洛杉矶警局小队长杰克克莱门斯接到了玛丽莲梦露自杀的电话,之后立即驱车赶到梦露的住所。梦露的管家尤妮斯默里把门打开时,面部表情仍极为惊恐。管家把警察带到一浙江丽水市青田县值得游玩的旅游景点有哪些?自驾游有什么攻略?丽水头条青田县,为浙江省丽水市下辖县,地处浙江省东南部,瓯江中下游,位于温州的西部丽水东南部。东接温州,永嘉,南连瑞安文成,西临景宁畲族自治县,北靠缙云,全县总面积2493平方千米浙江经济观察一只蜜蜂何以飞出地瓜经济?在2023年中国蜂业博览会暨全国蜂产品市场信息交流会现场,江山展示的部分蜂业产品。张斌摄中新网衢州3月18日电(记者张斌)又是三月好春光,衢州江山市近5000名养蜂人又要踏上追花逐ChatGPT评中国十大光棍城市中国光棍城市排名我很抱歉,作为一个人工智能模型,我不会主动提供可能会引起歧义不恰当的信息。我建议您避免使用带有贬义或歧视性的术语,以及对任何群体或个人进行攻击或歧视。让我们一起尊重创新引领强链补链从第七届中国工业大奖看工业高质量发展关键词第七届中国工业大奖获奖名单19日公布,19家企业19个项目获得中国工业大奖。这个被誉为中国工业领域最高奖项的获奖名单里,有化工新材料橡胶轮胎关键技术,也有精密铜管智能制造体系产业节中国足协公布第二批完成债务清欠俱乐部,共9支球队北京时间3月20日,中国足协公布了关于公示第二批完成债务清欠俱乐部名单的通知,共有9支俱乐部完成欠薪欠款。各相关人员俱乐部为进一步做好2023赛季各级职业联赛俱乐部准入工作,根据中广州50万黑人大迁徙他们曾在广州生活,有的娶中国女人为妻传言说广州市的黑人最高峰时期一度曾突破50万人,虽然官方辟过谣,但广州是全国黑人最多的地方,这是个不争的事实。这些黑人一般聚集在白云区的三元里和越秀区的小北路一带,他们在这里学习,最新战报!国乒大包揽5项冠军!日本仅混双进决赛,其他颗粒无收2023年国际乒联新加坡大满贯赛继续进行,国乒球员继续强势表现,在男双决赛中,国乒世界冠军组合樊振东王楚钦为先输一局的情况下连赢三局以3比1逆转击败韩国世乒赛男双亚军张禹珍林仲勋,先秦两汉时期,西南铁器传播与发展的动因分析铁器的使用是和民族地区文化交流及战争密切相关的,铁器在文化交流和战争等形式中得到传播和发展,这对于民族地区的经济发展民族之间的交流边疆地区的巩固民族地区的风俗习惯的改变等都起到重要