博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JS专题之数组去重
阅读量:6429 次
发布时间:2019-06-23

本文共 3794 字,大约阅读时间需要 12 分钟。

前言

数组去重在日常开发中的使用频率还是较高的,也是网上随便一抓一大把的话题,所以,我写这篇文章目的在于归纳和总结,既然很多人都在提的数组去重,自己到底了解多少呢。又或者是如果自己在开发中遇到了去重的需求,自己能想到更好的解决方案吗。

这次我们来理一理怎么做数组去重才能做得最合适,既要考虑兼容性,也要考虑性能和代码的优雅。

我的学习路径是模仿冴羽(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 value

function 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; i

sort 方法的优点在于利用了排序,返回后一个和前一个不相等的元素。比较简洁和直观。缺点在于改变了元素的本来的排序位置。

六、ES6 Set

ES6 提供了新的数据结构 Set,它类似于数组,但是成员的值都是唯一的,没有重复的值。向 Set 加入值的时候,不会发生类型转变,所以 5 和 '5' 是两个不同的值。Set内部判断两个值是否相同,用的是类似于 "==="的算法,但是区别是,在set内部认为NaN 等于 NaN ;

Set 可以转换为数组,所以很容易实现去重

function unique(origin) {    return Array.from(new Set(origin));}复制代码

七、ES6 Map

ES6 新增了 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的。

总结

数据去重在网上已经看烦了,但还是想专门写一篇文章来实践和总结,能在工作中多几个思路也是极好的。感谢那些热爱分享和喜欢输出的人。

参考链接:

转载地址:http://egnga.baihongyu.com/

你可能感兴趣的文章
React Native小白入门学习路径——二
查看>>
封装和内置函数property classmethod staticmethod
查看>>
9.22
查看>>
codeforces 599D Spongebob and Squares
查看>>
手机安全卫士——手机防盗页面
查看>>
java基础 逻辑
查看>>
找出数组中出现次数超过一半的数
查看>>
第十一次发博不知道用什么标题好
查看>>
收藏网址目录
查看>>
vue局部组件
查看>>
js行内式遇到的一些问题 DOM对象和jq对象转换的问题
查看>>
hoj1991 Happy 2005
查看>>
Django extra 和 annotate
查看>>
【转】ORACLE 表空间扩展方法
查看>>
[转载] 全本张广泰——第十五回 父子遇高人 原是同门亲
查看>>
Spring JdbcTemplate源码阅读报告
查看>>
查找SQL数据表或视图中的字段属性信息
查看>>
python3随机生成中文字符
查看>>
命令式和符号式混合编程
查看>>
yum 安装mongodb mysql
查看>>