数组去重经常被人拿来说事,虽然在工作中不常用,但他能够很好的考察js基础知识掌握的深度和广度,下面从js的不同阶段总结一下去重的方法。

ES3阶段

该阶段主要通过循环遍历数组从而达到去重的目的

  • 多次循环去掉重复元素
// 以下所有方法默认都那拿该数组进行测试
var array = [1, 1, '1', '1', null, null, undefined, undefined, new String('1'), new String('1'), /a/, /a/, NaN, NaN,{},{},[],[],{name: 'eric',sex: 'male'},{sex: 'male',name: 'eric'}];
function unique_es3_on2 (arr) {
var len = arr.length,
i = 0,
j,
flag,
ret = [];
for (; i < len ; i++) {
flag = true;
for (j = i+1 ; j < len ; j++) {
if (arr[i] === arr[j]) {
flag = false;
break;
}
}
if(flag) {
ret.push(arr[i]);
}
}
return ret;
}
unique_es3_on2(array)

结果如下图:

可见除了NaN没有去掉,其他效果都还挺好。原因就是NaN===NaN的结果是false。还有就是使用嵌套的循环,时间复杂度高,性能不是很好。

  • 借助新的对象单次循环去掉重复元素
function unique_es3_on(arr) {
var obj = {},
i,
len = arr.length,
ret = [];
for(i = 0; i < len ; i++) {
if(!obj[arr[i]]) {
obj[arr[i]] = true;
ret.push(arr[i]);
}
}
return ret;
}

结果如下图:

虽然时间复杂度不高了,但是效果并不好。因为对象的属性是字符串,所以会把数组所有元素默认转化为字符串,就会产生以下问题:

  1. 数值1和字符串'1'以及包装类型new String('1'),转化为字符串以后是相同的会被去掉。
  2. 对象转化为字符串以后会被误判,[]>'',{}>'[object Object]',还有就是形式相同,内存地址不同的对象会被去除。

为了解决类型转换以后出现的问题,可以用typeof操作符转一下:

function unique_es3_on(arr) {
var obj = {},
i,
len = arr.length,
str,
ret = [];
for(i = 0; i < len ; i++) {
str = typeof arr[i] + arr[i];
if(!obj[str]) {
obj[str] = true;
ret.push(arr[i]);
}
}
return ret;
}

结果如图:

可以看到类型转换的问题基本解决,但对象部分基本都被去除了,因为他们和字符串相加时还是会发生转化,解决的方案是把上面的str换成str = typeof arr[i] + JSON.stringify(arr[i]),相加之前先简单序列化一下。

结果如图:

从以上可以看出该阶段的各种方法或多或少的都有一些问题,该去除的没去掉,比如NaN。不该去的给去掉了,比如,形式相同但内存地址不同的对象(是否应该去掉全看你怎么定义)。

ES5阶段

function unique_es5(arr) {
return arr.filter(function(ele,index,array) {
return array.indexOf(ele) == index;
})
}

结果如图:

可以看到除了NaN,其他表现都是正常的。其中indexOf对于NaN总是返回-1,所以导致误判。

ES6阶段

let unique_includes = (arr) => {
let newArr = [];
arr.forEach(function(item){
if(!newArr.includes(item)){
newArr.push(item);
}
});
return newArr;
}

结果如图:

可以看到结果是符合预期的,es6中数组的扩展方法includes解决了用indexOf的弊端(不够直观,结果还要和索引进行比较。对NaN的误判)。

let unique_set = (arr) => {
return [...new Set(arr)];
}

结果和includes方法一样,此处利用es6新增数据结构set的特性,达到去重的目的。

let unique_map = (arr) => {
let ret = [],
m = new Map();
for(val of arr) {
if(!m.get(val)) {
m.set(val , true);
ret.push(val);
}
}
return ret;
}

结果和includes一样:

此处利用es6新增数据结构map的特性,之前的键值对集合(js对象),只能用字符串当作健,map这种数据结构打破了这一限制,各种类型的值都可以当作健,而且map的健是跟内存地址绑定的,只要内存地址不同就认为是不同的健,解决了之前形式相同而内存地址不同被去掉的问题。对于简单数据类型,只要严格相等就认为是相同的健,特例NaN也认为是相同的健。所以就解决了之前的两个大难题。

总结

虽然只是一个简单的去重问题,但这一路实践下来,可以看到js越来越强大,功能也越来越完善,同时也越来越优雅。

js数组去重方法分析与总结的更多相关文章

  1. js 数组去重方法汇总

    <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8&quo ...

  2. 原声js数组去重方法

    数组去重方法 方法一 ---- 利用数组filter + indexOf方法去重 方法二 ---- 利用数组forEach + indexOf方法去重 方法三 ---- 利用数组from方法 + Se ...

  3. Js数组去重方法总结

    //方法一 var arr = [1,23,1,1,1,3,23,5,6,7,9,9,8,5]; function removeDuplicatedItem(arr) { for(var i = 0; ...

  4. 三种常用的js数组去重方法

    第一种是比较常规的方法 思路: 1.构建一个新的数组存放结果 2.for循环中每次从原数组中取出一个元素,用这个元素循环与结果数组对比 3.若结果数组中没有该元素,则存到结果数组中 Array.pro ...

  5. js数组去重方法包括Es6(方法有很多,但是需要考虑兼容性和数据类型场景)

    1.Es6提供的方法 <script type="text/javascript"> //ES6里新添加了两个方法,set(set是一种新的数据结构,它可以接收一个数组 ...

  6. js 数组去重方法总结

    var arr = [1, 1, 'true', 'true', true, true, 15, 15, false, false, undefined, undefined, null, null, ...

  7. js数组去重方法整理

    1.思路:定义一个新数组,并存放原数组的第一个元素,然后将原数组的项和新数组的元素一一对比,若不同则存放在新数组中. function unique(arr){ var res = [arr[0]]; ...

  8. js数组去重方法集合

    //第一种方法,新建一个空数组,将原来的数组循环逐个与新数组的成员做比较,如果新数组没有该元素就push进来 var arr = ['a', 1, 1, 1, 2, 4, 4, 'b', 'c', ' ...

  9. js 数组去重方法

    var arr = ['a',1,2,3,'a',4,2,3,1,4,2,8,10,null,'a']; // 方法一 var newArr = [...new Set(arr)]; console. ...

随机推荐

  1. Intellj IDEA光标为insert状态,无法删除内容

    以前用得是社区版的IDEA,今天装了14版本的,结果导入项目后,发现打开java文件的光标是win系统下按了insert键后的那种宽的光标,并且还无法删除内容,且按删除(delete)键也只见光标往前 ...

  2. MySQL如何有效的存储IP地址及字符串IP和数值之间如何转换

    mysql> select inet_aton('192.168.0.1'); +--------------------------+ | inet_aton('192.168.0.1') | ...

  3. textarea禁止拖拽

    <textarea style="resize:none;" ></textarea>'

  4. 【LeetCode】258. Add Digits

    题目: Given a non-negative integer num, repeatedly add all its digits until the result has only one di ...

  5. Idea调试显示切换数据源的设置

    使用IDEA调试时,如果遇到相同方法会在编辑器上提示切换到哪个项目,因为手滑点了Disable,所以导致后来就不提示了,记录下设置方法.

  6. HDOJ 2209 贪心

    翻纸牌游戏 Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submi ...

  7. Kinect 常用识别手势

    以下手势能被流畅的识别: ◎RaiseRightHand / RaiseLeftHand – 左手或右手举起过肩并保持至少一秒 ◎Psi –双手举起过肩并保持至少一秒 ◎Stop – 双手下垂. ◎W ...

  8. zabbix的Java API(一)

    上文说了,我是对zabbix做第二次开发的小白,既然要对zabbix做第二次开发又是小白,那么就得来研究zabbix提供的相关API了. 于是我在zabbix网站各种找,终于在下面网址找到了: htt ...

  9. JAVA实用案例之水印开发

    写在最前面 上周零零碎碎花了一周的时间研究水印的开发,现在终于写了个入门级的Demo,做下笔记同时分享出来供大家参考. Demo是在我上次写的 JAVA实用案例之文件导入导出(POI方式) 框架基础上 ...

  10. js获取客户端MAC地址

    最近遇到一个需求,医院要求呼叫中心账号必须对应MAC地址,也就是说该MAC地址必须和呼叫中心账号对应才可使用,这可就难道我了,这需求就要求每次都判断用户登录的电脑MAC地址是否有呼叫中心账号,当然只针 ...