javascript数组去重的六种方法汇总


Posted in Javascript onAugust 16, 2015

面试前端必须准备的一个问题:怎样去掉Javascript的Array的重复项。据我所知,百度、腾讯、盛大等都在面试里出过这个题目。 这个问题看起来简单,但是其实暗藏杀机。 考的不仅仅是实现这个功能,更能看出你对计算机程序执行的深入理解。

    我总共想出了三种算法来实现这个目的:

Array.prototype.unique1 = function()
{
 var n = []; //一个新的临时数组
 for(var i = 0; i < this.length; i++) //遍历当前数组
 {
 //如果当前数组的第i已经保存进了临时数组,那么跳过,
 //否则把当前项push到临时数组里面
 if (n.indexOf(this[i]) == -1) n.push(this[i]);
 }
 return n;
}
Array.prototype.unique2 = function()
{
 var n = {},r=[]; //n为hash表,r为临时数组
 for(var i = 0; i < this.length; i++) //遍历当前数组
 {
 if (!n[this[i]]) //如果hash表中没有当前项
 {
  n[this[i]] = true; //存入hash表
  r.push(this[i]); //把当前数组的当前项push到临时数组里面
 }
 }
 return r;
}
Array.prototype.unique3 = function()
{
 var n = [this[0]]; //结果数组
 for(var i = 1; i < this.length; i++) //从第二项开始遍历
 {
 //如果当前数组的第i项在当前数组中第一次出现的位置不是i,
 //那么表示第i项是重复的,忽略掉。否则存入结果数组
 if (this.indexOf(this[i]) == i) n.push(this[i]);
 }
 return n;
}

    其中第1种和第3种方法都用到了数组的indexOf方法。此方法的目的是寻找存入参数在数组中第一次出现的位置。很显然,js引擎在实现这个方法的时候会遍历数组直到找到目标为止。所以此函数会浪费掉很多时间。 而第2中方法用的是hash表。把已经出现过的通过下标的形式存入一个object内。下标的引用要比用indexOf搜索数组快的多。

    为了判断这三种方法的效率如何,我做了一个测试程序,生成一个10000长度的随机数组成的数组,然后分别用几个方法来测试执行时间。 结果表明第二种方法远远快于其他两种方法。 但是内存占用方面应该第二种方法比较多,因为多了一个hash表。这就是所谓的空间换时间。  就是这个测试页面,你也可以去看看。

根据hpl大牛的思路,我写了第四种方法:

Array.prototype.unique4 = function()
{
 this.sort();
 var re=[this[0]];
 for(var i = 1; i < this.length; i++)
 {
 if( this[i] !== re[re.length-1])
 {
  re.push(this[i]);
 }
 }
 return re;
}

    这个方法的思路是先把数组排序,然后比较相邻的两个值。 排序的时候用的JS原生的sort方法,JS引擎内部应该是用的快速排序吧。 最终测试的结果是此方法运行时间平均是第二种方法的三倍左右,不过比第一种和第三种方法快了不少。

第五种方法

最近在做【搜索历史记录】功能也用到,开始用了 indexOf 方法,该方法在 ECMA5才有支持,对于 IE8- 就不支持了。

我们可以自己写一个函数(Array对象的方法都是定义在原型对象上的),如下:

Array.prototype.unique = function(){
  var length = this.length;
  if(length <= 1){
    return this;
  }
  if(!Array.prototype.indexOf){    
    Array.prototype.indexOf = function(item){
      var l = this.length, i = 0, r = -1;
      if(l <= 0){


 
return -1;



 }
      for(; i < l; i++){
        if(this[i] === item){
          r = i;
        }
      }
      return r;
    }
  }
  
  var result = []; //去重数组
  for(var i = 0; i < length; i++){
    if(result.indexOf(this[i]) === -1){
      result.push(this[i]);
    }
  }
  return result;
}

第六种方法

Array类型并没有提供去重复的方法,如果要把数组的重复元素干掉,那得自己想办法:

function unique(arr) {
  var result = [], isRepeated;
  for (var i = 0, len = arr.length; i < len; i++) {
    isRepeated = false;
    for (var j = 0, len = result.length; j < len; j++) {
      if (arr[i] == result[j]) {  
        isRepeated = true;
        break;
      }
    }
    if (!isRepeated) {
      result.push(arr[i]);
    }
  }
  return result;
}

总体思路是把数组元素逐个搬运到另一个数组,搬运的过程中检查这个元素是否有重复,如果有就直接丢掉。从嵌套循环就可以看出,这种方法效率极低。我们可以 用一个hashtable的结构记录已有的元素,这样就可以避免内层循环。

Javascript 相关文章推荐
一个不错的应用,用于提交获取文章内容,不推荐用
Mar 03 Javascript
jQuery 入门级学习笔记及源码
Jan 22 Javascript
jquery ajax return没有返回值的解决方法
Oct 20 Javascript
javascript中this做事件参数相关问题解答
Mar 17 Javascript
文本有关的样式和jQuery求对象的高宽问题分别说明
Aug 30 Javascript
Js与Jq 获取页面元素值的方法和差异对比
Apr 30 Javascript
纯js代码制作的网页时钟特效【附实例】
Mar 30 Javascript
AngularJS中的$watch(),$digest()和$apply()区分
Apr 04 Javascript
javascript 解决浏览器不支持的问题
Sep 24 Javascript
深入理解Node.js的HTTP模块
Oct 12 Javascript
Node.js之readline模块的使用详解
Mar 25 Javascript
前端监听websocket消息并实时弹出(实例代码)
Nov 27 Javascript
JS+CSS实现下拉列表框美化效果(3款)
Aug 15 #Javascript
js时钟翻牌效果实现代码分享
Jul 31 #Javascript
js实现点击文本框显示日期选择器特效代码分享
May 21 #Javascript
jQuery树形下拉菜单特效代码分享
Aug 15 #Javascript
Jquery幻灯片特效代码分享--打开页面随机选择切换方式(3)
Aug 15 #Javascript
jQuery幻灯片特效代码分享--鼠标滑过按钮时切换(2)
Nov 18 #Javascript
Jquery幻灯片特效代码分享--鼠标点击按钮时切换(1)
Aug 15 #Javascript
You might like
php 保留小数点
2009/04/21 PHP
基于PHP+jQuery+MySql实现红蓝(顶踩)投票代码
2015/08/25 PHP
PHP抓取远程图片(含不带后缀的)教程详解
2016/10/21 PHP
DEDE实现转跳属性文档在模板上调用出转跳地址
2016/11/04 PHP
javascript 全等号运算符使用说明
2010/05/31 Javascript
JavaScript 页面编码与浏览器类型判断代码
2010/06/03 Javascript
JQuery在页面中添加和除移DOM示例代码
2013/06/24 Javascript
解决jquery插件冲突的问题
2014/01/23 Javascript
详解JavaScript基于面向对象之继承实例
2015/12/16 Javascript
JS动态加载脚本并执行回调操作
2016/08/24 Javascript
bootstrap实现每隔5秒自动轮播效果
2016/12/20 Javascript
Angular ng-repeat指令实例以及扩展部分
2016/12/26 Javascript
详解vue.js+UEditor集成 [前后端分离项目]
2017/07/07 Javascript
JavaScript中防止微信浏览器被整体拖动的方法
2017/08/25 Javascript
Bootstrap实现的表格合并单元格示例
2018/02/06 Javascript
原生js实现抽奖小游戏
2019/06/27 Javascript
vue data变量相互赋值后被实时同步的解决步骤
2020/08/05 Javascript
微信小程序对图片进行canvas压缩的方法示例详解
2020/11/12 Javascript
Ruby使用eventmachine为HTTP服务器添加文件下载功能
2016/04/20 Python
TensorFlow实现MLP多层感知机模型
2018/03/09 Python
python之pandas用法大全
2018/03/13 Python
浅谈DataFrame和SparkSql取值误区
2018/06/09 Python
浅谈pyqt5中信号与槽的认识
2019/02/17 Python
详解Python3网络爬虫(二):利用urllib.urlopen向有道翻译发送数据获得翻译结果
2019/05/07 Python
python 反编译exe文件为py文件的实例代码
2019/06/27 Python
PyTorch: 梯度下降及反向传播的实例详解
2019/08/20 Python
pytorch 中pad函数toch.nn.functional.pad()的用法
2020/01/08 Python
pytorch实现CNN卷积神经网络
2020/02/19 Python
Jupyter Notebook 文件默认目录的查看以及更改步骤
2020/04/14 Python
Python操作Excel的学习笔记
2021/02/18 Python
pycharm Tab键设置成4个空格的操作
2021/02/26 Python
CSS3 linear-gradient线性渐变生成加号和减号的方法
2017/11/21 HTML / CSS
夜班门卫岗位职责
2013/12/09 职场文书
医学专业职业生涯规划范文
2014/02/05 职场文书
2014年预备党员端正入党动机思想汇报
2014/09/13 职场文书
win10蓝屏0xc0000001安全模式进不了怎么办?win10出现0xc0000001的解决方法
2022/08/05 数码科技