JavaScript 高性能数组去重的方法


Posted in Javascript onSeptember 20, 2018

中午和同事吃饭,席间讨论到数组去重这一问题

我立刻就分享了我常用的一个去重方法,随即被老大指出这个方法效率不高

回家后我自己测试了一下,发现那个方法确实很慢

于是就有了这一次的高性能数组去重研究

一、测试模版

数组去重是一个老生常谈的问题,网上流传着有各种各样的解法

为了测试这些解法的性能,我写了一个测试模版,用来计算数组去重的耗时

// distinct.js
let arr1 = Array.from(new Array(100000), (x, index)=>{
 return index
})
let arr2 = Array.from(new Array(50000), (x, index)=>{
 return index+index
})
let start = new Date().getTime()
console.log('开始数组去重')
function distinct(a, b) {
 // 数组去重
}
console.log('去重后的长度', distinct(arr1, arr2).length)
let end = new Date().getTime()
console.log('耗时', end - start)

这里分别创建了两个长度为 10W 和 5W 的数组

然后通过 distinct() 方法合并两个数组,并去掉其中的重复项

数据量不大也不小,但已经能说明一些问题了

二、Array.filter() + indexOf

这个方法的思路是,将两个数组拼接为一个数组,然后使用 ES6 中的 Array.filter() 遍历数组,并结合 indexOf 来排除重复项

function distinct(a, b) {
 let arr = a.concat(b);
 return arr.filter((item, index)=> {
 return arr.indexOf(item) === index
 })
}

这就是我被吐槽的那个数组去重方法,看起来非常简洁,但实际性能。。。

JavaScript 高性能数组去重的方法

是的,现实就是这么残酷,处理一个长度为 15W 的数组都需要 8427ms

三、双重 for 循环

最容易理解的方法,外层循环遍历元素,内层循环检查是否重复

当有重复值的时候,可以使用 push(),也可以使用 splice()

function distinct(a, b) {
 let arr = a.concat(b);
 for (let i=0, len=arr.length; i<len; i++) {
 for (let j=i+1; j<len; j++) {
  if (arr[i] == arr[j]) {
  arr.splice(j, 1);
  // splice 会改变数组长度,所以要将数组长度 len 和下标 j 减一
  len--;
  j--;
  }
 }
 }
 return arr
}

但这种方法占用的内存较高,效率也是最低的

JavaScript 高性能数组去重的方法

四、for...of + includes()

双重for循环的升级版,外层用 for...of 语句替换 for 循环,把内层循环改为 includes()

先创建一个空数组,当 includes() 返回 false 的时候,就将该元素 push 到空数组中

类似的,还可以用 indexOf() 来替代 includes()

function distinct(a, b) {
 let arr = a.concat(b)
 let result = []
 for (let i of arr) {
 !result.includes(i) && result.push(i)
 }
 return result
}

这种方法和 filter + indexOf 挺类似

只是把 filter() 的内部逻辑用 for 循环实现出来,再把 indexOf 换为 includes

所以时长上也比较接近

JavaScript 高性能数组去重的方法

五、Array.sort()

首先使用 sort() 将数组进行排序

然后比较相邻元素是否相等,从而排除重复项

function distinct(a, b) {
 let arr = a.concat(b)
 arr = arr.sort()
 let result = [arr[0]]
 for (let i=1, len=arr.length; i<len; i++) {
 arr[i] !== arr[i-1] && result.push(arr[i])
 }
 return result
}

这种方法只做了一次排序和一次循环,所以效率会比上面的方法都要高

JavaScript 高性能数组去重的方法

六、new Set()

ES6 新增了 Set 这一数据结构,类似于数组,但 Set 的成员具有唯一性

基于这一特性,就非常适合用来做数组去重了

function distinct(a, b) {
 return Array.from(new Set([...a, ...b]))
}

那使用 Set 又需要多久时间来处理 15W 的数据呢?

JavaScript 高性能数组去重的方法

喵喵喵??? 57ms ??我没眼花吧??

然后我在两个数组长度后面分别加了一个0,在 150W 的数据量之下...

JavaScript 高性能数组去重的方法

居然有如此高性能且简洁的数组去重办法?!

七、for...of + Object

这个方法我只在一些文章里见过,实际工作中倒没怎么用

首先创建一个空对象,然后用 for 循环遍历

利用对象的属性不会重复这一特性,校验数组元素是否重复

function distinct(a, b) {
 let arr = a.concat(b)
 let result = []
 let obj = {}
 for (let i of arr) {
 if (!obj[i]) {
  result.push(i)
  obj[i] = 1
 }
 }
 return result
}

当我看到这个方法的处理时长,我又傻眼了

JavaScript 高性能数组去重的方法

15W 的数据居然只要 16ms ??? 比 Set() 还快???

然后我又试了试 150W 的数据量...

JavaScript 高性能数组去重的方法

总结

以上所述是小编给大家介绍的JavaScript 高性能数组去重的方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
通过event对象的fromElement属性解决热区设置主实体的一个bug
Dec 22 Javascript
jquery 子窗口操作父窗口的代码
Sep 21 Javascript
JQuery,Extjs,YUI,Prototype,Dojo 等JS框架的区别和应用场景简述
Apr 15 Javascript
简单谈谈javascript代码复用模式
Jan 28 Javascript
jQuery实现的多级下拉菜单效果代码
Aug 24 Javascript
vue.js通过自定义指令实现数据拉取更新的实现方法
Oct 18 Javascript
jquery利用json实现页面之间传值的实例解析
Dec 12 Javascript
Vue不能检测到Object/Array更新的情况的解决
Jun 26 Javascript
jQuery选择器之层次选择器用法实例分析
Feb 19 jQuery
vue响应式系统之observe、watcher、dep的源码解析
Apr 09 Javascript
浅析webpack-bundle-analyzer在vue-cli3中的使用
Oct 23 Javascript
vue使用原生swiper代码实例
Feb 05 Javascript
vue2 设置router-view默认路径的实例
Sep 20 #Javascript
vue实现同一个页面可以有多个router-view的方法
Sep 20 #Javascript
vuejs router history 配置到iis的方法
Sep 20 #Javascript
关于单文件组件.vue的使用
Sep 20 #Javascript
vue-cli 打包使用history模式的后端配置实例
Sep 20 #Javascript
jQuery pjax 应用简单示例
Sep 20 #jQuery
微信小程序scroll-view横向滑动嵌套for循环的示例代码
Sep 20 #Javascript
You might like
使用字符串函数输出整数化的PHP版本号
2006/10/09 PHP
php eval函数用法总结
2012/10/31 PHP
php Xdebug的安装与使用详解
2013/06/20 PHP
php中session过期时间设置及session回收机制介绍
2014/05/05 PHP
PHP错误Parse error: syntax error, unexpected end of file in test.php on line 12解决方法
2014/06/23 PHP
php实现模拟登陆方正教务系统抓取课表
2015/05/19 PHP
php_pdo 预处理语句详解
2016/11/21 PHP
基于jQuery的Tab选项框效果代码(插件)
2011/03/01 Javascript
node.js中的fs.appendFile方法使用说明
2014/12/17 Javascript
IE下支持文本框和密码框placeholder效果的JQuery插件分享
2015/01/31 Javascript
基于JQuery实现仿网易邮箱全屏动感滚动插件fullPage
2015/09/20 Javascript
浅析Ajax语法
2016/12/05 Javascript
微信小程序之数据双向绑定与数据操作
2017/05/12 Javascript
ComboBox(下拉列表框)通过url加载调用远程数据的方法
2017/08/06 Javascript
JavaScript中Object值合并方法详解
2017/12/22 Javascript
详解如何快速配置webpack多入口脚手架
2018/12/28 Javascript
vue数据更新UI不刷新显示的解决办法
2020/08/06 Javascript
深入讲解Python编程中的字符串
2015/10/14 Python
利用TensorFlow训练简单的二分类神经网络模型的方法
2018/03/05 Python
Python基于更相减损术实现求解最大公约数的方法
2018/04/04 Python
python编辑用户登入界面的实现代码
2018/07/16 Python
Python二进制串转换为通用字符串的方法
2018/07/23 Python
Python3.5常见内置方法参数用法实例详解
2019/04/29 Python
Pytorch 搭建分类回归神经网络并用GPU进行加速的例子
2020/01/09 Python
谈一谈数组拼接tf.concat()和np.concatenate()的区别
2020/02/07 Python
详解Python中string模块除去Str还剩下什么
2020/11/30 Python
pycharm 实现复制一行的快捷键
2021/01/15 Python
澳大利亚票务和娱乐市场领导者:Ticketmaster
2017/03/03 全球购物
英国豪华文具和皮具配件经典老品牌:Smythson(斯迈森)
2018/04/19 全球购物
社区七一党员活动方案
2014/01/25 职场文书
财务信息服务专业自荐书范文
2014/02/08 职场文书
不尊敬老师检讨书范文
2014/11/19 职场文书
三峡导游词
2015/01/31 职场文书
2015年教师节慰问信
2015/03/23 职场文书
自主招生学校推荐信范文
2015/03/26 职场文书
2019年让高校“心动”的自荐信
2019/03/25 职场文书