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 相关文章推荐
很酷的javascript loading效果代码
Jun 18 Javascript
js中parseFloat(参数1,参数2)定义和用法及注意事项
Jan 27 Javascript
jquery数组封装使用方法分享(jquery数组遍历)
Mar 25 Javascript
Javascript 是你的高阶函数(高级应用)
Jun 15 Javascript
Jquery1.9.1源码分析系列(六)延时对象应用之jQuery.ready
Nov 24 Javascript
jQuery事件绑定用法详解(附bind和live的区别)
Jan 19 Javascript
AngularJS应用开发思维之依赖注入3
Aug 19 Javascript
Bootstrap基本样式学习笔记之图片(6)
Dec 07 Javascript
EditPlus 正则表达式 实战(3)
Dec 15 Javascript
微信小程序 Button 组件详解及简单实例
Jan 10 Javascript
vue2.x 通过后端接口代理,获取qq音乐api的数据示例
Oct 30 Javascript
js利用拖放实现添加删除
Aug 27 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 5昨天隆重推出--PHP 5/Zend Engine 2.0新特性
2006/10/09 PHP
MVC模式的PHP实现
2006/10/09 PHP
PHP 中文乱码解决办法总结分析
2009/07/30 PHP
javascript模拟实现C# String.format函数功能代码
2013/11/25 Javascript
解决Extjs4中form表单提交后无法进入success函数问题
2013/11/26 Javascript
关于js内存泄露的一个好例子
2013/12/09 Javascript
jQuery实现QQ空间汉字转拼音功能示例
2017/07/10 jQuery
vue proxyTable 接口跨域请求调试的示例
2017/09/12 Javascript
webpack 打包压缩js和css的方法示例
2018/03/20 Javascript
基于vue-simplemde实现图片拖拽、粘贴功能
2018/04/12 Javascript
解析vue路由异步组件和懒加载案例
2018/06/08 Javascript
详解webpack2异步加载套路
2018/09/14 Javascript
分享5个顶级的JavaScript Ajax组件库
2018/09/16 Javascript
javascript实现函数柯里化与反柯里化过程解析
2019/10/08 Javascript
vue自定义树状结构图的实现方法
2020/10/18 Javascript
教你用 Python 实现微信跳一跳(Mac+iOS版)
2018/01/04 Python
利用python 更新ssh 远程代码 操作远程服务器的实现代码
2018/02/08 Python
Python离线安装PIL 模块的方法
2019/01/08 Python
Python 图像对比度增强的几种方法(小结)
2019/09/25 Python
Python网络编程之使用TCP方式传输文件操作示例
2019/11/01 Python
Python读取YAML文件过程详解
2019/12/30 Python
用python写爬虫简单吗
2020/07/28 Python
Django前后端分离csrf token获取方式
2020/12/25 Python
丝芙兰美国官网:SEPHORA美国
2016/08/03 全球购物
手工制作的意大利太阳镜和光学元件:Illesteva
2019/01/19 全球购物
Java 中访问数据库的步骤?Statement 和PreparedStatement 之间的区别?
2012/06/05 面试题
寝室长工作失责检讨书
2014/10/06 职场文书
2014年政风行风工作总结
2014/11/22 职场文书
计划生育汇报材料
2014/12/26 职场文书
新员工考核评语
2014/12/31 职场文书
幼儿园教师自我评价
2015/03/04 职场文书
学校勤俭节约倡议书
2015/04/29 职场文书
2015入党自传书范文
2015/06/26 职场文书
初中数学教学随笔
2015/08/15 职场文书
2020年个人安全保证书参考模板
2020/01/08 职场文书
i5-10400f处理相当于i7多少水平
2022/04/19 数码科技