摘要:将元素作为对象的键,默认键对应的值为如果对象中没有这个键,则将这个元素放入结果数组中去。
前言
数组去重在日常开发中的使用频率还是较高的,也是网上随便一抓一大把的话题,所以,我写这篇文章目的在于归纳和总结,既然很多人都在提的数组去重,自己到底了解多少呢。又或者是如果自己在开发中遇到了去重的需求,自己能想到更好的解决方案吗。
这次我们来理一理怎么做数组去重才能做得最合适,既要考虑兼容性,也要考虑性能和代码的优雅。
我的学习路径是模仿冴羽(github: mqyqingfeng)的学习方式,感谢像冴羽这样优秀的人在前面领跑,我不想光看不做,所以多实践多输出,希望未来能走出我自己的路。
一、入门方案function unique(origin) { var result = []; for(var i = 0; i < origin.length; i++) { var arrayItem = origin[i]; for(var j= 0; j< result.length; j++) { var resultItem = result[j]; // 如果在结果数组循环中找到了该元素,则跳出循环,进入下一个源数组元素的判断 if(resultItem === arrayItem) { break; } } // 如果把结果数组循环完都没有找到该元素,就将该元素压入结果数组中 if(j === result.length) { result.push(arrayItem); } } return result; } var array = ["a", "b", "c", "1", 0, "c", 1, "", 1, 0]; console.log(unique(array)); // ["a", "b", "c", "1", 0, 1, ""]
以上代码是最简单实现数组去重的方式,优点在于兼容性极好,缺点就是两次 for 循环,时间复杂度为 O(n^2),性能较差。
二、数组的 indexOf 属性数组中的 indexOf 属性是 ES5 的规范,只有 IE8 及更早版本不支持该方法。相对来说,如果你不需要兼容 IE8 的话,尽量用 indexOf 来判断一个元素是否在数组中。
function unique(origin){ var result = []; for(var i = 0; i< origin.length; i++) { var item = origin[i]; if(result.indexOf(item) === -1) { result.push(item); } } return result; }三、数组的 filter 属性
数组的 filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
filter 的回调有三个参数,其中第三个参数是当前元素属于的数组对象,这样我们可以继续利用 indexOf 属性啦。
function unique(origin) { var result = origin.filter(function (item, index, array){ // 获取元素在源数组的位置,只返回那些索引等于当前元素索引的值。 return array.indexOf(item) === index; }); return result; }
filter 兼容到 IE9, 这种方法没有 for 循环,主要利用了 filter 和 indexOf 属性,所以代码相对比较优雅。
四、利用 Object 的 key valuefunction unique(origin) { var result = []; var hashTable = {}; for(var i = 0; i< origin.length; i++) { // 如果键对应的值,为真,意味着对象的键中已经有重复的键了。 if(!hashTable[origin[i]]) { // 将元素作为对象的键,默认键对应的值为 true, hashTable[origin[i]] = true; // 如果对象中没有这个键,则将这个元素放入结果数组中去。 result.push(origin[i]); } } return result; }
这种方案的事件复杂度为 O(n), 但是对象的键,默认是字符串类型,这意味着什么呢,数字 1 和 字符串 "1",在键中是相等的,所以,上面这种方法不适合字符串和数字混合的去重。
所以我们将元素的类型也放入对象的键中:
function unique(origin) { var result = []; var hashTable = {}; for(var i = 0; i< origin.length; i++) { var current = origin[i]; // 字符串拼接元素的类型和元素 var key = typeof(current) + current; if(!hashTable[key]) { hashTable[key] = true; result.push(current); } } return result; }五、数组的 sort 方法
function unique(origin) { return origin.concat.sort().filter(function(item, index, array) { // !index 表示第 0 个元素应该被返回。 return !index || item !== origin[index-1] }) } function unique(array) { array.sort(); // 排序字符串 array.sort(function(a, b) { return a-b; // 排序数字 }) for(let i=0; isort 方法的优点在于利用了排序,返回后一个和前一个不相等的元素。比较简洁和直观。缺点在于改变了元素的本来的排序位置。
六、ES6 SetES6 提供了新的数据结构 Set,它类似于数组,但是成员的值都是唯一的,没有重复的值。向 Set 加入值的时候,不会发生类型转变,所以 5 和 "5" 是两个不同的值。Set内部判断两个值是否相同,用的是类似于 "==="的算法,但是区别是,在set内部认为NaN 等于 NaN ;
Set 可以转换为数组,所以很容易实现去重
function unique(origin) { return Array.from(new Set(origin)); }七、ES6 MapES6 新增了 Map 数据结果,通过 has 和 set 方法就能很方便的对前面的 object key value 方案进行优化。
function unique(origin){ const map = new Map() return origin.filter((item) => !map.has(item) && map.set(item, true)) }八、类型判断一些常见的数据类型是 === 和 indexOf 是无法检测的,举个例子:
console.log({} === {}) // false; console.log(NaN === NaN) // false; console.log(/a/ === /a/); // false; console.log(1 === new String("1")) // false; var arr = [NaN]; console.log(arr.indexOf(NaN)); // -1所以在判断的时候,如果数据里有 NaN 和对象时要避免使用 indexOf 和 ===;
前面 Set 那里说过了,所以 Set 方法是可以去重 NaN的。
总结数据去重在网上已经看烦了,但还是想专门写一篇文章来实践和总结,能在工作中多几个思路也是极好的。感谢那些热爱分享和喜欢输出的人。
欢迎关注我的个人公众号“谢南波”,专注分享原创文章。
掘金专栏 JavaScript 系列文章JavaScript之变量及作用域
JavaScript之声明提升
JavaScript之执行上下文
JavaScript之变量对象
JavaScript之原型与原型链
JavaScript之作用域链
JavaScript之闭包
JavaScript之this
JavaScript之arguments
JavaScript之按值传递
JavaScript之例题中彻底理解this
JavaScript专题之模拟实现call和apply
JavaScript专题之模拟实现bind
JavaScript专题之模拟实现new
JS专题之事件模型
JS专题之事件循环
JS专题之去抖函数
JS专题之节流函数
JS专题之函数柯里化
JS专题之数组去重
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/108916.html
摘要:专题系列共计篇,主要研究日常开发中一些功能点的实现,比如防抖节流去重类型判断拷贝最值扁平柯里递归乱序排序等,特点是研究专题之函数组合专题系列第十六篇,讲解函数组合,并且使用柯里化和函数组合实现模式需求我们需要写一个函数,输入,返回。 JavaScript 专题之从零实现 jQuery 的 extend JavaScritp 专题系列第七篇,讲解如何从零实现一个 jQuery 的 ext...
距离上次发文,已经有一段时间了,最近工作比较忙,这不眼看快双十一了,就相当于给大家一些福利吧! showImg(https://segmentfault.com/img/remote/1460000016538082?w=250&h=250); 一、什么是数组去重 简单说就是把数组中重复的项删除掉,你 GET 到了吗 ?下面我将简单介绍下几种基本的方法及其优缺点。 二、方法汇总 两层循环 无相同...
摘要:写在前面专题系列是我写的第二个系列,第一个系列是深入系列。专题系列自月日发布第一篇文章,到月日发布最后一篇,感谢各位朋友的收藏点赞,鼓励指正。 写在前面 JavaScript 专题系列是我写的第二个系列,第一个系列是 JavaScript 深入系列。 JavaScript 专题系列共计 20 篇,主要研究日常开发中一些功能点的实现,比如防抖、节流、去重、类型判断、拷贝、最值、扁平、柯里...
摘要:专题系列第三篇,讲解各种数组去重方法,并且跟着写一个前言数组去重方法老生常谈,既然是常谈,我也来谈谈。它类似于数组,但是成员的值都是唯一的,没有重复的值。 JavaScript 专题系列第三篇,讲解各种数组去重方法,并且跟着 underscore 写一个 unique API 前言 数组去重方法老生常谈,既然是常谈,我也来谈谈。 双层循环 也许我们首先想到的是使用 indexOf 来循...
阅读 2541·2021-11-25 09:43
阅读 1830·2021-09-22 15:26
阅读 3589·2019-08-30 15:56
阅读 1685·2019-08-30 15:55
阅读 1871·2019-08-30 15:54
阅读 789·2019-08-30 15:52
阅读 3112·2019-08-29 16:23
阅读 872·2019-08-29 12:43