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 相关文章推荐
来自国外的14个图片放大编辑的jQuery插件整理
Oct 20 Javascript
Jquery中获取iframe的代码
Jan 11 Javascript
浅谈关于JavaScript的语言特性分析
Apr 11 Javascript
SpringMVC restful 注解之@RequestBody进行json与object转换
Dec 10 Javascript
Node.js项目中调用JavaScript的EJS模板库的方法
Mar 11 Javascript
Java  Spring 事务回滚详解
Oct 17 Javascript
jQuery图片切换动画效果
Feb 28 Javascript
使用Vuex实现一个笔记应用的方法
Mar 13 Javascript
JS中判断某个字符串是否包含另一个字符串的五种方法
May 03 Javascript
Vue项目history模式下微信分享爬坑总结
Mar 29 Javascript
微信小程序本地存储实现每日签到、连续签到功能
Oct 09 Javascript
vue项目配置sass及引入外部scss文件
Apr 14 Vue.js
手写实现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
一些星际专用术语解释
2020/03/04 星际争霸
需要注意的几个PHP漏洞小结
2012/02/05 PHP
php实现将数组转换为XML的方法
2015/03/09 PHP
百度地图经纬度转换到腾讯地图/Google 对应的经纬度
2015/08/28 PHP
php面向对象程序设计中self与static的区别分析
2019/05/21 PHP
php计数排序算法的实现代码(附四个实例代码)
2020/03/31 PHP
索趣科技的答案
2007/02/07 Javascript
javascript中的作用域scope介绍
2010/12/28 Javascript
让图片旋转任意角度及JQuery插件使用介绍
2013/03/20 Javascript
jQuery在html有效在jsp无效的原因及解决方法
2013/08/02 Javascript
jQuery插件开发的两种方法及$.fn.extend的详解
2014/01/16 Javascript
node.js中的require使用详解
2014/12/15 Javascript
jQuery实现简单的间隔向上滚动效果
2015/03/09 Javascript
jquery之别踩白块游戏的简单实现
2016/07/25 Javascript
vue2中filter()的实现代码
2017/07/09 Javascript
小程序实现发表评论功能
2018/07/06 Javascript
angular4自定义表单控件[(ngModel)]的实现
2018/11/23 Javascript
javascript实现异形滚动轮播
2019/11/28 Javascript
vue element-ul实现展开和收起功能的实例代码
2020/11/25 Vue.js
[06:57]DOTA2-DPC中国联赛 正赛 Ehome vs PSG.LGD 选手采访
2021/03/11 DOTA
python在windows命令行下输出彩色文字的方法
2015/03/19 Python
Python序列操作之进阶篇
2016/12/08 Python
利用Python中unittest实现简单的单元测试实例详解
2017/01/09 Python
django orm 通过related_name反向查询的方法
2018/12/15 Python
python频繁写入文件时提速的方法
2019/06/26 Python
django框架面向对象ORM模型继承用法实例分析
2019/07/29 Python
基于python 取余问题(%)详解
2020/06/03 Python
IE滤镜与CSS3效果(详细整理分享)
2013/01/25 HTML / CSS
canvas如何实现多张图片编辑的图片编辑器
2020/03/10 HTML / CSS
叙述DBMS对数据控制功能有哪些
2016/06/12 面试题
Linux如何命名文件--使用文件名时应注意
2014/05/29 面试题
幼师岗位求职简历的自荐信格式
2013/09/21 职场文书
旅游管理毕业生自荐信
2013/11/05 职场文书
公司财务总监岗位职责
2013/12/14 职场文书
学生打架检讨书大全
2014/01/23 职场文书
《两个铁球同时着地》教学反思
2014/02/13 职场文书