JS数组去重详情


Posted in Javascript onNovember 07, 2021

1 测试用例

// 测试用例
const a = {};
const b = { c: 1 };
const array = [
  1, 1, "1", "1",
  {}, {}, { c: 1 }, { c: 1},
  a, a, b, b, 
  [], [], [1], [1],
  undefined, undefined,
  null, null,
  NaN, NaN,
];

2 JS 数组去重4大类型

2.1 元素比较型

此类型通过数组元素之间进行比较来去重

2.1.1 双层 for 循环逐一比较(es5常用)

使用双层for循环逐一比较数组元素,用splice方法去除重复的元素

// 双层for循环
function uniq1(arr) {
    for (let i = 0; i < arr.length; i++) {
        for (let j = i + 1; j < arr.length; j++) {
            if (arr[i] === arr[j]) {
                arr.splice(j, 1)
                j--
            }
        }
    }
    return arr
}

// 去重结果
// [1,'1',{},{},{c:1},{c:1},{},{c:1},[],[],[1],[1],undefined,null,NaN,NaN]

通过对比去重前后结果,重复的NaN没有去掉,因为NaN === NaNfalse

2.1.2 排序相邻比较

使用sort()方法对数组元素进行排序,然后比较相邻元素,用splice方法去除重复的元素。

function uni2(arr) {
    arr.sort();
    for (let i = 0; i < arr.length - 1; i++) {
        arr[i] === arr[i + 1] && arr.splice(i + 1, 1) && i--;
    }
    return arr;
}

也可以创建新数组,将不重复的元素放入新数组中

function uniq3(arr) {
    arr = arr.sort()
    const newArr = [arr[0]]
    for (let i = 1; i < arr.length; i++) {
        if (arr[i] !== arr[i - 1]) {
            newArr.push(arr[i])
        }
    }
    return newArr
}

// 去重结果
// [[],[],1,'1',[1],[1],NaN,NaN,{},{},{c:1},{c:1},{},{c:1},null,undefined]

重复的NaN没有去掉,因为NaN === NaN为false
sort
默认排序顺序是将元素转换为字符串,对象转换为字符串都是[object Object] ,所以sort方法不能对数组中的对象进行排序,也就有可能无法去除重复的对象,除非重复的对象本就相邻

2.2 查找元素位置型

此类型通过查找元素第一次出现的位置来去重

2.2.1 indexOf

通过indexOf查找当前元素第一次出现的位置是否为当前位置,若是,则放入新数组

function uniq4(arr) {
    let res = []
    for (let i = 0; i < arr.length; i++) {
        if (arr.indexOf(arr[i]) === i) {
            res.push(arr[i])
        }
    }
    return res
}

// 去重结果
// [1,'1',{},{},{c:1},{c:1},{},{c:1},[],[],[1],[1],undefined,null]

同样,因为NaN === NaNfalse,所以用indexOf查找NaN结果总是-1,从而在新数组中不会有NaN

2.2.2 findIndex

通过findIndex查找当前元素第一次出现的位置是否为当前位置,若是,则放入新数组

function uniq5(arr) {
    let res = []
    for (let i = 0; i < arr.length; i++) {
        if (arr.findIndex(item => item === arr[i]) === i) {
            res.push(arr[i])
        }
    }
    return res
}
// 去重结果
// [1,'1',{},{},{c:1},{c:1},{},{c:1},[],[],[1],[1],undefined,null]

同样,因为NaN === NaNfalse,所以用findIndex查找NaN结果总是-1,从而在新数组中不会有NaN

2.3 元素是否存在型

此类型通过判断在新数组中是否存在当前元素来去重

2.3.1 includes

includes方法用来判断一个数组是否包含一个指定的值

function uniq6(arr) {
    let res = []
    for (let i = 0; i < arr.length; i++) {
        if (!res.includes(arr[i])) {
            res.push(arr[i])
        }
    }
    return res
}
// 去重结果
// [1,'1',{},{},{c:1},{c:1},{},{c:1},[],[],[1],[1],undefined,null,NaN]

includes使用零值相等算法来确定是否找到给定的元素,所以可以判断NaN是否在新数组中存在

2.3.2 some

some方法用来测试数组中是否至少有1个元素通过了被提供的函数测试

function uniq7(arr) {
    let res = []
    for (let i = 0; i < arr.length; i++) {
        if (!res.some(item => item === arr[i])) {
            res.push(arr[i])
        }
    }
    return res
}
// 去重结果
// [1,'1',{},{},{c:1},{c:1},{},{c:1},[],[],[1],[1],undefined,null,NaN,NaN]

同样,这里仍旧使用了===来比较元素,因为NaN === NaNfalse,所以新数组中会有多个NaN

2.4 依托数据结构特性

此类型通过ES6提供的数据结构MapSet本身不可重复特性来去重

2.4.1 Map

ES6提供的Map结构可以用各种类型的值(包括对象)当作键,且键是唯一的

function uniq8(arr) {
    const map = new Map()
    for (let i = 0; i < arr.length; i++) {
        !map.has(arr[i]) && map.set(arr[i], true)
    }
    return [...map.keys()]
}
// 去重结果
// [1,'1',{},{},{c:1},{c:1},{},{c:1},[],[],[1],[1],undefined,null,NaN]

map.has方法对NaN也有效

2.4.2 Set(ES6 最常用)

Set结构的成员的值都是唯一的,没有重复的值。

function uniq9(arr) {
    return [...new Set(arr)]
}

// 去重结果
// [1,'1',{},{},{c:1},{c:1},{},{c:1},[],[],[1],[1],undefined,null,NaN]

3 补充

上面所说的方法可以使用不同的Api进行改动,比如使用splice方法去除数组元素的地方,我们可以通过filter方法来过滤数组得到新数组;

再比如includes的方法中不用for循环遍历数组,通过reduce方法来代替等等。

总之,方法有很多,但是万变不离其宗

有些去重方法对NaN无效,因为NaN === NaNfalse,如果有需求,可以使用Object.is(NaN, NaN)true来进行修改

实际应用中,最常用的方法就是使用Set,也可以使用第三方库lodash来处理

到此这篇关于JS数组去重详情的文章就介绍到这了,更多相关JS数组去重内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
jquery控制listbox中项的移动并排序的实现代码
Sep 28 Javascript
用javascript作一个通用向导说明
Aug 30 Javascript
封装了一个支持匿名函数的Javascript事件监听器
Jun 05 Javascript
JavaScript学习笔记整理之引用类型
Jan 22 Javascript
jQuery实现下拉框左右移动(全部移动,已选移动)
Apr 15 Javascript
Bootstrap的Refresh Icon也spin起来
Jul 13 Javascript
关于Function中的bind()示例详解
Dec 02 Javascript
使用JavaScript实现表格编辑器(实例讲解)
Aug 02 Javascript
JS非空验证及邮箱验证的实例
Aug 11 Javascript
从零开始最小实现react服务器渲染详解
Jan 26 Javascript
Vue 组件复用多次自定义参数操作
Jul 27 Javascript
处理JavaScript值为undefined的7个小技巧
Jul 28 Javascript
手写实现JS中的new
Nov 07 #Javascript
用JS写一个发布订阅模式
Nov 07 #Javascript
浅谈JavaScript浅拷贝和深拷贝
JavaScript严格模式不支持八进制的问题讲解
Javascript使用integrity属性进行安全验证
Nov 07 #Javascript
JavaScript中时间格式化新思路toLocaleString()
Nov 07 #Javascript
JavaScript中isPrototypeOf函数
You might like
如何在PHP程序中防止盗链
2008/04/09 PHP
php开发过程中关于继承的使用方法分享
2011/06/17 PHP
php制作文本式留言板
2015/03/18 PHP
php将日期格式转换成xx天前的格式
2015/04/16 PHP
php实现图片缩略图的方法
2016/03/29 PHP
微信接口生成带参数的二维码
2017/07/31 PHP
PHP PDOStatement::setAttribute讲解
2019/02/01 PHP
JS 控制非法字符的输入代码
2009/12/04 Javascript
JQuery写动态树示例代码
2013/07/31 Javascript
JS实现5秒钟自动封锁div层的方法
2015/02/20 Javascript
JavaScript中的substr()方法使用详解
2015/06/06 Javascript
JavaScript 控制字体大小设置的方法
2016/11/23 Javascript
Javascript实现倒计时(防页面刷新)实例
2016/12/13 Javascript
Vue.js实现表格动态增加删除的方法(附源码下载)
2017/01/20 Javascript
通过button将form表单的数据提交到action层的实例
2017/09/08 Javascript
JavaScript实现随机数生成器(去重)
2017/10/13 Javascript
微信小程序出现wx.navigateTo页面不跳转问题的解决方法
2017/12/26 Javascript
多页vue应用的单页面打包方法(内含打包模式的应用)
2020/06/11 Javascript
Python中处理unchecked未捕获异常实例
2015/01/17 Python
利用python程序帮大家清理windows垃圾
2017/01/15 Python
Python开发最牛逼的IDE——pycharm
2018/08/01 Python
Python爬取个人微信朋友信息操作示例
2018/08/03 Python
python合并已经存在的sheet数据到新sheet的方法
2018/12/11 Python
python实现差分隐私Laplace机制详解
2019/11/25 Python
python opencv实现简易画图板
2020/08/27 Python
python实现录音功能(可随时停止录音)
2020/10/26 Python
Melijoe时尚童装德国官网:Melijoe德国
2016/09/03 全球购物
出国留学自荐信
2013/10/25 职场文书
圣诞节红领巾广播稿
2014/02/03 职场文书
重点工程汇报材料
2014/08/27 职场文书
乡镇党委书记第三阶段个人整改措施
2014/09/16 职场文书
司法局群众路线教育实践活动开展情况总结
2014/10/25 职场文书
月考总结与反思
2015/10/22 职场文书
2016年万圣节活动个人总结
2016/04/05 职场文书
不会写演讲稿,快来看看这篇文章!
2019/08/06 职场文书
Vue3 Composition API的使用简介
2021/03/29 Vue.js