JS- 数组去重方法整理

摘要:
==temp[temp.length-1]){8温度按钮9}10}11返回温度;12} 13控制台日志;//缺点是无法添加字符串14console.log//缺点是我们无法添加字符串1functionuniq4{2array.sort;5vartemp=[array[0];//关键点是将第一个字符串放入6for{//i,从17if(array[i]开始! 当我们的变量是数字12时,我们将调用在数字构造类的数字原型上重写的toString方法,以获得字符串“12”。当我们使用上面的方法时,一个缺点是当数组嵌入了对象和数组值时,因为obj[key-value]将被字符串化,导致稍后出现的多个对象将被视为重复,因此我们需要在obj中存储值时处理这种情况。需要消除重复的数组:首先查看初始写入方法:1functionuniq0517{2varobj={};3varrst=[];每个(el=˃{5if(!

indexOf

简单而且可以加中文,但是兼容性不好,indexOF兼容到ie9

 1 function uniq(arr) {
 2     var temp = [];
 3     for (let i = 0; i < arr.length; i++) {
 4         if (temp.indexOf(arr[i]) == -1) {
 5             temp.push(arr[i])
 6         }
 7     }
 8     return temp;
 9 }
10 console.log(uniq([1, 2, 3, 2, 34, "a", "b", "a", 2, 5, 2, 62, ]));

【排序后相邻去除法】

简单,去重排序一起做。但必须是纯数组,不能在数字中混入字符串

 1 function uniq3(array) {
 2   array.sort((a, b) => {
 3     return a - b
 4   });
 5   var temp = [array[0]]; //关键点,先把第一个放进去
 6   for (let i = 1; i < array.length; i++) { //i从1开始
 7     if (array[i] !== temp[temp.length - 1]) {
 8       temp.push(array[i])
 9     }
10   }
11   return temp;
12 }
13 console.log(uniq3([1, 2, 1, 2, 12, 13, 235, 3])); // 缺点就是不能加入字符串
14 console.log(uniq3([1, 2, "b", 1, 2, 12, 13, 235, 3, "a"])); // 缺点就是不能加入字符串

 

【根据上边改成数组中字符串排序去重法】

 1 function uniq4(array) {
 2   array.sort((a, b) => {
 3     return (a+'').charCodeAt() - (b+'').charCodeAt()
 4   });
 5   var temp = [array[0]]; //关键点,先把第一个放进去
 6   for (let i = 1; i < array.length; i++) { //i从1开始
 7     if (array[i] !== temp[temp.length - 1]) {
 8       temp.push(array[i])
 9     }
10   }
11   return temp;
12 }
13 console.log(uniq4(['w', 'a', "b", 'w', 'n', 's', 's', 'b', 'e', "a"])); // 缺点就是不能混入别的

 

【存到对象里一一对比,去重无排序】

 

思路 - 利用对象的hash键值对方法,快速获取的特点

准备一个对象和一个新数组,

循环原数组时,将数组的值当做对象的键,且对应值为true/1皆可),

然后每次拿原数组的下一个值都去判断一下对象中是否有这个值,

没有再push到新数组中去,最后返回新数组。

 1 uniqArr: function (arr) {
 2     var arr = Array.prototype.slice.call(arr),//这里防止伪数组,容错
 3         obj = {},
 4         newArr = [];
 5         obj[arr[0]] = true;//这里没必要
 6         newArr.push(arr[0]);
 7     arr.forEach((el) => {
 8         if (!obj[el]) {//但是这样写,又一个问题,见下边总结
 9             obj[el] = true;//这里写成true,if里少一步隐式转换
10             newArr.push(el);
11         }
12     });
13     return newArr;
14 }

 

总结:

 

这种写法有一个问题,就是当我们arr中有多个不一样的对象元素(比如[1,{val:212},'a',{c: 1},false,{d:2}]这样时,会发现,只留下了第一个对象{val:212}这样。

 

控制台效果:

JS- 数组去重方法整理第1张

 

这是因为一个对象值当做obj的键名时会被toString化,得到的是obj['[object Object]'],后边再有对象时在forEach判断里条件不会成立,就不会被push到新数组,因此也就会被过滤掉了。

 

其原理同这个题:

1 var a = {};b = {m: 1};c ={n:2};
2 
3 a[b] = 'b';
4 
5 a[c] = 'c';

JS- 数组去重方法整理第2张

a当中,键名不叫b也不叫c,而是b这个对象被Object.prototype.toString化后的字符串[object Object]。就是同一个原理。

 

因为我们使用[]来给对象a追加属性,在[]中,是期望是一个字符串类型的值,所以里边的值会被"字符串化"

 

也就是当我们传的变量是一个{}时,对象会调用自身原型上的Object.prototype.toString进行转化变成字符串[object Object]

 

当我们变量是一个数字12,会调用数字的构造类Number原型上重写的toString方法得到一个字符串'12'

 

反正都是会转成字符串。即使当变量转为字符串后为特殊值(如NaN)等也不例外:

 JS- 数组去重方法整理第3张

 

以上边的缺点引出下边的方法:

  

【一行代码实现数组去重】

1 let newArr = [...new Set([1, 2, 23, 1, "gjf", 1, 6, "gjf","gfj"])]
2 console.log(newArr)

// 核心

[…new Set([..需要去重的数组..])]

 

 

【缺点方法的解决】

 

上边说道【存到对象里,一一对比进行去重】方法时,有一个缺点是数组内嵌套了对象、数组这些值时,

 

因为obj[键值]会被字符串化,导致后边出现的多个对象都会被当做重复处理,

 

所以我们需要在往obj里存值时对这种情况进行一下处理

 

需要去重的数组:

JS- 数组去重方法整理第4张

先看最初的写法:

 1 function uniq0517(arr){
 2     var obj = {};
 3     var rst = [];
 4     arr.forEach(el => {
 5         if(!obj[el]){
 6             obj[el] = true;
 7             rst.push(el);
 8         }
 9     });
10     console.log(obj);// 注意下打印的obj
11     return rst;
12 }

目标:去掉重复的对象和数组以及其他原始值,但是保留不同的对象和数组.

 

去重后的结果:

 JS- 数组去重方法整理第5张

 

观察发现,除了对象外,都完成了很好的效果。

 

看打印的obj结果分析问题:

 JS- 数组去重方法整理第6张

因为数组在obj的中括号[]里进行toString后是字符串'1,23,4'这样,所以可以比较不同。

 

但是对象不行。对象一律是[object Object]这样,需要对对象进行处理:

 

我的思路是,如果检测值为对象(就是普通的对象,而不是时间、正则等这种对象,

 

所以需要toString检测)时,就把这个对象先JSON.stringify化了。再去进行对比。

 

就像下面这样,JSON.stringify过后的对象绝对可以判断是否全等。

JS- 数组去重方法整理第7张

 

 

因此数组去重改造过后的代码如下:

 1 function uniq0517(arr){
 2     var obj = {},
 3         rst = [],
 4         tempEl = '';
 5     arr.forEach(el => {
 6         if(Object.prototype.toString.call(el) === '[object Object]'){
 7             // 证明这个值是一个对象,就事先将对象字符串化。而不是让他调用自己的toString
 8             tempEl = JSON.stringify(el);
 9         }else{
10             // 其他类型的值时不做改变
11             tempEl = el;
12         }
13         if(!obj[tempEl]){
14             obj[tempEl] = true;
15             rst.push(el);
16         }
17     });
18     console.log(obj);
19     return rst;
20 }

 

完美经过检验!

 

 

最后拓展,想着把临时obj换成Map数据结构改造一下:

 

 1 function uni10519(arr){
 2     // 用Map实现去重 - 但凡引用值都不能去重
 3     let map = new Map(),
 4         rst = [];
 5     arr.forEach(el => {
 6         if(!map.get(el)){// 已有的一个对象再获取,因为地址不同,所以得到false
 7             map.set(el,true);
 8             rst.push(el);
 9         }
10     });
11     console.log(map);
12     return rst;
13 }
14 console.log('map试水失败',uni10519(arr20190517));

算了吧。。。引用值地址不同,没法取出来作对比。

 

同样的,对于这种超级复杂类型的数组,进行去重的话,还得用我最原始的方式进行一一比对。否则set也扑街了:

1 function uni10519Set(arr) {
2     // 用Set实现去重 
3     return [...new Set(arr)];
4 }
5 console.log('set试水失败',uni10519Set(arr20190517));// 对象、数组什么的引用值都不能比较相等

 

 

 

免责声明:文章转载自《JS- 数组去重方法整理》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇C# .NET 中的缓存实现matlab练习程序(PSNR)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

jQuery和原生JS的对比

原生JS的缺点: 不能添加多个入口函数(window.onload),如果添加了多个,后面的会把前面的覆盖掉 原生js的api名字太长,难以书写,不易记住 原生js有的代码冗余 原生js中的属性或者方法有些浏览器无法兼容 原生js容错率比较低,前面的代码出现问题,后面的代码执行不到 jQuery的优点: 可以写多个入口函数 jQuery的api名字容...

详解 JS 中 new 调用函数原理

JavaScript 中经常使用构造函数创建对象(通过 new 操作符调用一个函数),那在使用 new 调用一个函数的时候到底发生了什么?先看几个例子,再解释背后发生了什么。 1)看三个例子 1.1 无 return 语句 构造函数最后没有 return 语句,这也是使用构造函数时默认情况,最后会返回一个新对象,如下: function Foo(age)...

AJAX技术框架及开发工具 转

常见的AJAX框架有: DWR - Web Remoting Buffalo - Web Remoting (based on prototype) prototype - JS OO library openrico - JS UI component (based on prototype) dojo - JS library and UI co...

js实现图片的等比例缩放

  js实现图片的等比例缩放 CreateTime--2018年3月6日14:04:18 Author:Marydon 1.代码展示 /** * 图片按宽高比例进行自动缩放 * @param ImgObj * 缩放图片源对象 * @param maxWidth * 允许缩放的最大宽度 * @param maxHei...

h5页面跳转小程序

2020年以前, 只能通过 web-view内嵌h5跳转小程序,现在  可以直接跳了!!!!!!  官方文档:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_Open_Tag.html 用的是JS-SDK的接口,需要使用到js-sdk-1.6.0的版本才有支持,htt...

JS事件 鼠标经过事件(onmouseover)鼠标经过事件,当鼠标移到一个对象上时,该对象就触发onmouseover事件,并执行onmouseover事件调用的程序。

鼠标经过事件(onmouseover) 鼠标经过事件,当鼠标移到一个对象上时,该对象就触发onmouseover事件,并执行onmouseover事件调用的程序。 现实鼠标经过"确定"按钮时,触发onmouseover事件,调用函数info(),弹出消息框,代码如下: 运行结果:   任务 补充右边编辑器第13行,当鼠标经过"确定...