js数组去重的常用方法总结


Posted in Javascript onJanuary 24, 2014

JS实现数组去重(重复的元素只保留一个)

1、遍历数组法

1.遍历数组法

它是最简单的数组去重方法(indexOf方法)

实现思路:新建一个数组,遍历去要重的数组,当值不在新数组的时候(indexOf为-1)就加入该新数组中;

例子1

function unique(arr) {
  if (!Array.isArray(arr)) {
    console.log('type error!')
    return
  }
  var array = [];
  for (var i = 0; i < arr.length; i++) {
    if (array .indexOf(arr[i]) === -1) {
      array .push(arr[i])
    }
  }
  return array;
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
  // [1, "true", true, 15, false, undefined, null, NaN, NaN, "NaN", 0, "a", {…}, {…}] //NaN、{}没有去重

例子2

var arr=[2,8,5,0,5,2,6,7,2];
function unique1(arr){
 var hash=[];
 for (var i = 0; i < arr.length; i++) {
   if(hash.indexOf(arr[i])==-1){
   hash.push(arr[i]);
   }
 }
 return hash;
}

2.数组下标判断法

调用indexOf方法,性能和方法1差不多

实现思路:如果当前数组的第 i 项在当前数组中第一次出现的位置不是 i,那么表示第 i 项是重复的,忽略掉。否则存入结果数组。

function unique2(arr){
 var hash=[];
 for (var i = 0; i < arr.length; i++) {
   if(arr.indexOf(arr[i])==i){
   hash.push(arr[i]);
   }
 }
 return hash;
}

3.排序后相邻去除法

实现思路:给传入的数组排序,排序后相同的值会相邻,然后遍历排序后数组时,新数组只加入不与前一值重复的值。

function unique3(arr){
 arr.sort();
 var hash=[arr[0]];
 for (var i = 1; i < arr.length; i++) {
   if(arr[i]!=hash[hash.length-1]){
   hash.push(arr[i]);
   }
 }
 return hash;
}

4.优化遍历数组法(不推荐)

实现思路:双层循环,外循环表示从0到arr.length,内循环表示从i+1到arr.length

将没重复的右边值放入新数组。(检测到有重复值时终止当前循环同时进入外层循环的下一轮判断)

function unique4(arr){
 var hash=[];
 for (var i = 0; i < arr.length; i++) {
  for (var j = i+1; j < arr.length; j++) {
   if(arr[i]===arr[j]){
    ++i;
   }
  }
   hash.push(arr[i]);
 }
 return hash;
}

上面遍历经过测试后有bug,并不能完全去重

js数组去重的常用方法总结

因为这次我做的是对js对象元素去重,我在参考时发现此bug,如果时数组去重,建议用第一种方法。

js数组去重的常用方法总结

quan_lst 里面是一个一个的js字面量对象,根据json里面的属性进行判定去重

function unique(quan_lst){  
//去掉重复选取的数据
  for (var i = 0; i < quan_lst.length; i++) {
    for (var j =i+1; j <quan_lst.length; ) {
      if (quan_lst[i].photoid == quan_lst[j].photoid ) {//通过photoid属性进行匹配;
        quan_lst.splice(j, 1);//去除重复的对象;
      }else {
        j++;
      }
    }
  }
}

5.ES6实现

基本思路:ES6提供了新的数据结构Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。

Set函数可以接受一个数组(或类似数组的对象)作为参数,用来初始化。

function unique5(arr){
 var x = new Set(arr);
 return [...x];
}

利用ES6 Set去重(ES6中最常用)

function unique (arr) {
 return Array.from(new Set(arr))
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
 //[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {}, {}]

扩展:如果重复,则去掉该元素

数组下标去重

function unique22(arr){
 var hash=[];
 for (var i = 0; i < arr.length; i++) {
   if(arr.indexOf(arr[i])==arr.lastIndexOf(arr[i])){
   hash.push(arr[i]);
   }
 }
 return hash;
}

补充:原先自己一直以为indexOf是针对字符串,原来indexOf也可以查询出数组元素所在的数组中的位置(以0开始计算),
以上转自于轩悦的博客,学了很多思路。

6、利用sort()

利用sort()排序方法,然后根据排序后的结果进行遍历及相邻元素比对。

function unique(arr) {
  if (!Array.isArray(arr)) {
    console.log('type error!')
    return;
  }
  arr = arr.sort()
  var arrry= [arr[0]];
  for (var i = 1; i < arr.length; i++) {
    if (arr[i] !== arr[i-1]) {
      arrry.push(arr[i]);
    }
  }
  return arrry;
}
   var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
    console.log(unique(arr))
// [0, 1, 15, "NaN", NaN, NaN, {…}, {…}, "a", false, null, true, "true", undefined]   //NaN、{}没有去重

7、利用includes

includes 检测数组是否有某个值

function unique(arr) {
  if (!Array.isArray(arr)) {
    console.log('type error!')
    return
  }
  var array =[];
  for(var i = 0; i < arr.length; i++) {
      if( !array.includes( arr[i]) ) {//includes 检测数组是否有某个值
          array.push(arr[i]);
       }
  }
  return array
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
  console.log(unique(arr))
  //[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}, {…}]   //{}没有去重

八、利用for嵌套for,然后splice去重(ES5中最常用)推荐

双层循环,外层循环元素,内层循环时比较值。值相同时,则删去这个值。

function unique(arr){      
    for(var i=0; i<arr.length; i++){
      for(var j=i+1; j<arr.length; j++){
        if(arr[i]==arr[j]){     //第一个等同于第二个,splice方法删除第二个
          arr.splice(j,1);
          j--;
        }
      }
    }
return arr;
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
  console.log(unique(arr))
  //[1, "true", 15, false, undefined, NaN, NaN, "NaN", "a", {…}, {…}]   //NaN和{}没有去重,两个null直接消失了

9、利用对象的属性不能相同的特点进行去重(这种数组去重的方法有问题,不建议用,有待改进)

function unique(arr) {
  if (!Array.isArray(arr)) {
    console.log('type error!')
    return
  }
  var arrry= [];
   var obj = {};
  for (var i = 0; i < arr.length; i++) {
    if (!obj[arr[i]]) {
      arrry.push(arr[i])
      obj[arr[i]] = 1
    } else {
      obj[arr[i]]++
    }
  }
  return arrry;
}
  var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
    console.log(unique(arr))
//[1, "true", 15, false, undefined, null, NaN, 0, "a", {…}]  //两个true直接去掉了,NaN和{}去重

十、利用hasOwnProperty

利用hasOwnProperty 判断是否存在对象属性

function unique(arr) {
  var obj = {};
  return arr.filter(function(item, index, arr){
    return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
  })
}
  var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
    console.log(unique(arr))
//[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}]  //所有的都去重了

十一、利用filter

function unique(arr) {
 return arr.filter(function(item, index, arr) {
  //当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素
  return arr.indexOf(item, 0) === index;
 });
}
  var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
    console.log(unique(arr))
//[1, "true", true, 15, false, undefined, null, "NaN", 0, "a", {…}, {…}]

十二、利用递归去重

function unique(arr) {
    var array= arr;
    var len = array.length;

  array.sort(function(a,b){  //排序后更加方便去重
    return a - b;
  })

  function loop(index){
    if(index >= 1){
      if(array[index] === array[index-1]){
        array.splice(index,1);
      }
      loop(index - 1);  //递归loop,然后数组去重
    }
  }
  loop(len-1);
  return array;
}
 var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "a", "true", true, 15, false, 1, {…}, null, NaN, NaN, "NaN", 0, "a", {…}, undefined]

十三、利用Map数据结构去重

创建一个空Map数据结构,遍历需要去重的数组,把数组的每一个元素作为key存到Map中。由于Map中不会出现相同的key值,所以最终得到的就是去重后的结果。

function unique(arr){
  return arr.reduce((prev,cur) => prev.includes(cur) ? prev : [...prev,cur],[]);
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr));
// [1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}, {…}]

十四、利用reduce+includes

function unique(arr){
  return arr.reduce((prev,cur) => prev.includes(cur) ? prev : [...prev,cur],[]);
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr));
// [1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}, {…}]

十五、[...new Set(arr)]

[...new Set(arr)] 
//代码就是这么少----(其实,严格来说并不算是一种,相对于第一种方法来说只是简化了代码)

PS:有些文章提到了foreach+indexOf数组去重的方法,个人觉得都是大同小异,所以没有写上去。

下面是其他网友的补充

第一种是比较常规的方法

思路:

1.构建一个新的数组存放结果

2.for循环中每次从原数组中取出一个元素,用这个元素循环与结果数组对比

3.若结果数组中没有该元素,则存到结果数组中

Array.prototype.unique1 = function(){
 var res = [this[0]];
 for(var i = 1; i < this.length; i++){
 var repeat = false;
 for(var j = 0; j < res.length; j++){
  if(this[i] == res[j]){
  repeat = true;
  break;
  }
 }
 if(!repeat){
  res.push(this[i]);
 }
 }
 return res;
}
var arr = [1, 'a', 'a', 'b', 'd', 'e', 'e', 1, 0]
alert(arr.unique1());

第二种方法比上面的方法效率要高

思路:

1.先将原数组进行排序

2.检查原数组中的第i个元素 与 结果数组中的最后一个元素是否相同,因为已经排序,所以重复元素会在相邻位置

3.如果不相同,则将该元素存入结果数组中

Array.prototype.unique2 = function(){
 this.sort(); //先排序
 var res = [this[0]];
 for(var i = 1; i < this.length; i++){
 if(this[i] !== res[res.length - 1]){
  res.push(this[i]);
 }
 }
 return res;
}
var arr = [1, 'a', 'a', 'b', 'd', 'e', 'e', 1, 0]
alert(arr.unique2());

第二种方法也会有一定的局限性,因为在去重前进行了排序,所以最后返回的去重结果也是排序后的。如果要求不改变数组的顺序去重,那这种方法便不可取了。

第三种方法(推荐使用)

思路:

1.创建一个新的数组存放结果

2.创建一个空对象

3.for循环时,每次取出一个元素与对象进行对比,如果这个元素不重复,则把它存放到结果数组中,同时把这个元素的内容作为对象的一个属性,并赋值为1,存入到第2步建立的对象中。

说明:至于如何对比,就是每次从原数组中取出一个元素,然后到对象中去访问这个属性,如果能访问到值,则说明重复。

Array.prototype.unique3 = function(){
 var res = [];
 var json = {};
 for(var i = 0; i < this.length; i++){
 if(!json[this[i]]){
  res.push(this[i]);
  json[this[i]] = 1;
 }
 }
 return res;
}

var arr = [112,112,34,'你好',112,112,34,'你好','str','str1'];
alert(arr.unique3());

以上就是js数组去重的三种常用方法总结的详细内容,更多关于js数组去重的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
js 页面传参数时 参数值含特殊字符的问题
Dec 13 Javascript
jQuery UI的Dialog无法提交问题的解决方法
Jan 11 Javascript
jquery滚动条插件jScrollPane的使用介绍
Nov 08 Javascript
js使用removeChild方法动态删除div元素
Aug 01 Javascript
Javascript 拖拽雏形中的一些问题(逐行分析代码,让你轻松了拖拽的原理)
Jan 23 Javascript
JavaScript控制listbox列表框的项目上下移动的方法
Mar 18 Javascript
angular4 如何在全局设置路由跳转动画的方法
Aug 30 Javascript
QQ跳转支付宝并自动领红包脚本(最新)
Jun 22 Javascript
利用JS动态生成隔行换色HTML表格的两种方法
Oct 09 Javascript
JS实现li标签的删除
Apr 12 Javascript
ES6中的Javascript解构的实现
Oct 30 Javascript
JQuery的$和其它JS发生冲突的快速解决方法
Jan 24 #Javascript
js判断60秒以及倒计时示例代码
Jan 24 #Javascript
innerText 使用示例
Jan 23 #Javascript
登陆成功后自动计算秒数执行跳转
Jan 23 #Javascript
检查输入的是否是数字使用keyCode配合onkeypress事件
Jan 23 #Javascript
html dom节点操作(获取/修改/添加或删除)
Jan 23 #Javascript
解决jquery插件冲突的问题
Jan 23 #Javascript
You might like
《心理测量者3》剧场版动画预告
2020/03/02 日漫
星际争霸教主Flash的ID由来:你永远不会知道他之前的ID是www!
2019/01/18 星际争霸
亚洲咖啡有什么?亚洲咖啡产地介绍 亚洲咖啡有什么特点?
2021/03/05 新手入门
php实现的发送带附件邮件类实例
2014/09/22 PHP
如何在PHP中使用数组
2020/06/09 PHP
jQuery 获取URL参数的插件
2010/03/04 Javascript
浅谈tudou土豆网首页图片延迟加载的效果
2010/06/23 Javascript
20款超赞的jQuery插件 Web开发人员必备
2011/02/26 Javascript
基于jquery的web页面日期格式化插件
2011/11/15 Javascript
jquery 操作DOM的基本用法分享
2012/04/05 Javascript
十个迅速提升JQuery性能让你的JQuery跑得更快
2012/12/10 Javascript
JS图片根据鼠标滚动延时加载的实例代码
2013/07/13 Javascript
当前页禁止复制粘贴截屏代码小集
2013/07/24 Javascript
JS判断客户端是手机还是PC的2个代码
2014/04/12 Javascript
基于JavaScript实现Tab选项卡切换效果
2016/11/24 Javascript
浅析js的模块化编写 require.js
2016/12/07 Javascript
Vue.use源码分析
2017/04/22 Javascript
值得收藏的vuejs安装教程
2017/11/21 Javascript
vue最简单的前后端交互示例详解
2018/10/11 Javascript
python MySQLdb使用教程详解
2018/03/20 Python
利用Python代码实现数据可视化的5种方法详解
2018/03/25 Python
对TensorFlow的assign赋值用法详解
2018/07/30 Python
Python连接Impala实现步骤解析
2020/08/04 Python
Python如何测试stdout输出
2020/08/10 Python
HTML5 Canvas draw方法制作动画效果示例
2013/07/11 HTML / CSS
纽约通行卡:The New York Pass(免费游览纽约90多个景点)
2017/07/29 全球购物
纽约手袋品牌:KARA
2018/03/18 全球购物
俄罗斯天然和有机产品、健康生活网上商店:Fitomarket.ru
2020/10/09 全球购物
如何查找和删除数据库中的重复数据
2014/11/05 面试题
外贸英语专业求职信范文
2013/12/25 职场文书
公务员政审单位鉴定材料
2014/05/16 职场文书
博士生专家推荐信
2015/03/25 职场文书
学校捐书活动总结
2015/05/08 职场文书
2019年教师节活动策划方案
2019/09/09 职场文书
python设置 matplotlib 正确显示中文的四种方式
2021/05/10 Python
图文详解Nginx版本平滑升级方案
2021/09/15 Servers