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 相关文章推荐
8个超棒的学习 jQuery 的网站 推荐收藏
Apr 02 Javascript
EditPlus注册码生成器(js代码实现)
Mar 25 Javascript
JavaScript保留两位小数的2个自定义函数
May 05 Javascript
javascript解析json数据的3种方式
May 08 Javascript
js强制把网址设为默认首页
Sep 29 Javascript
浅谈JavaScript 标准对象
Jun 02 Javascript
JavaScript实现相册弹窗功能(zepto.js)
Jun 21 Javascript
JS身份证信息验证正则表达式
Jun 12 Javascript
JavaScript中Object基础内部方法图
Feb 05 Javascript
JavaScript原型链与继承操作实例总结
Aug 24 Javascript
微信小程序实现的绘制table表格功能示例
Apr 26 Javascript
Vue form表单动态添加组件实战案例
Sep 02 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
ThinkPHP调试模式与日志记录概述
2014/08/22 PHP
php查询mssql出现乱码的解决方法
2014/12/29 PHP
php将html转成wml的WAP标记语言实例
2015/07/08 PHP
js 学习笔记(三)
2009/12/29 Javascript
关于div自适应高度/左右高度自适应一致的js代码
2013/03/22 Javascript
结合JQ1.9通过js正则判断各种浏览器版本的方法
2013/12/30 Javascript
jQuery中odd选择器的定义和用法
2014/12/23 Javascript
jQuery实现图片文字淡入淡出效果
2015/12/21 Javascript
js实现百度地图定位于地址逆解析,显示自己当前的地理位置
2016/12/08 Javascript
微信小程序 用户数据解密详细介绍
2017/01/09 Javascript
jQuery获取Table某列的值(推荐)
2017/03/03 Javascript
vue如何集成raphael.js中国地图的方法示例
2017/08/15 Javascript
使用vs code开发Nodejs程序的使用方法
2017/09/21 NodeJs
vue父组件向子组件传递多个数据的实例
2018/03/01 Javascript
在Vue mounted方法中使用data变量详解
2019/11/05 Javascript
js中Function引用类型常见有用的方法和属性详解
2019/12/11 Javascript
jquery实现进度条状态展示
2020/03/26 jQuery
js实现菜单跳转效果
2020/12/11 Javascript
更改Ubuntu默认python版本的两种方法python-&gt; Anaconda
2016/12/18 Python
python算法与数据结构之单链表的实现代码
2019/06/27 Python
vim自动补全插件YouCompleteMe(YCM)安装过程解析
2019/10/21 Python
Pycharm及python安装详细步骤及PyCharm配置整理(推荐)
2020/07/31 Python
python 通过文件夹导入包的操作
2020/06/01 Python
HTML5移动开发图片压缩上传功能
2016/11/09 HTML / CSS
澳大利亚儿童和婴儿产品在线商店:Lime Tree Kids
2017/10/05 全球购物
viagogo意大利票务平台:演唱会、体育比赛、戏剧门票
2018/01/26 全球购物
size?德国官方网站:英国伦敦的球鞋精品店
2018/03/17 全球购物
银河香水:Galaxy Perfume
2019/03/25 全球购物
Vector, ArrayList, HashTable, HashMap哪些是线程安全的,哪些不是
2015/10/12 面试题
总经理司机岗位职责
2014/02/06 职场文书
开业庆典策划方案
2014/02/18 职场文书
反腐倡廉警示教育活动总结
2014/05/05 职场文书
2015年个人思想总结
2015/03/09 职场文书
利用ajax+php实现商品价格计算
2021/03/31 PHP
MySql学习笔记之事务隔离级别详解
2021/05/12 MySQL
springboot中的pom文件 project报错问题
2022/01/18 Java/Android