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 日期处理之时区问题
Oct 08 Javascript
Web 前端设计模式--Dom重构 提高显示性能
Oct 22 Javascript
JS实现文字向下滚动完整实例
Feb 06 Javascript
jQuery基于ajax实现带动画效果无刷新柱状图投票代码
Aug 10 Javascript
实例代码详解javascript实现窗口抖动及qq窗口抖动
Jan 04 Javascript
浅谈jQuery this和$(this)的区别及获取$(this)子元素对象的方法
Nov 29 Javascript
详解Angular 4 表单快速入门
Jun 05 Javascript
使用 Vue 绑定单个或多个 Class 名的实例代码
Jan 08 Javascript
vue中各种通信传值方式总结
Feb 14 Javascript
4 种滚动吸顶实现方式的比较
Apr 09 Javascript
浅谈Node 异步IO和事件循环
May 05 Javascript
微信小程序点击列表跳转到对应详情页过程解析
Sep 26 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
一个简单的自动发送邮件系统(一)
2006/10/09 PHP
phpMyAdmin 安装教程全攻略
2007/03/19 PHP
php下的权限算法的实现
2007/04/28 PHP
PHP PDO函数库详解
2010/04/27 PHP
一个基于phpQuery的php通用采集类分享
2014/04/09 PHP
php获取ajax的headers方法与内容实例
2017/12/27 PHP
Yii框架小部件(Widgets)用法实例详解
2020/05/15 PHP
在Javascript中为String对象添加trim,ltrim,rtrim方法
2006/09/22 Javascript
jquery高效反选具体实现
2013/05/05 Javascript
js实现键盘Enter键提交表单的方法
2015/05/27 Javascript
学习AngularJs:Directive指令用法(完整版)
2016/04/26 Javascript
js简单实现图片延迟加载的方法
2016/07/19 Javascript
js 获取元素所有兄弟节点的实现方法
2016/09/06 Javascript
微信小程序去哪里找 小程序到底如何使用(附小程序名单)
2017/01/09 Javascript
利用Vue v-model实现一个自定义的表单组件
2017/04/27 Javascript
vue+element-ui集成随机验证码+用户名+密码的form表单验证功能
2018/08/05 Javascript
vue通过video.js解决m3u8视频播放格式的方法
2019/07/30 Javascript
详解JavaScript中的链式调用
2020/11/27 Javascript
Python开发常用的一些开源Package分享
2015/02/14 Python
Python获取任意xml节点值的方法
2015/05/05 Python
python开发之thread实现布朗运动的方法
2015/11/11 Python
Python简单读取json文件功能示例
2017/11/30 Python
python 接口测试response返回数据对比的方法
2018/02/11 Python
python 读写文件,按行修改文件的方法
2018/07/12 Python
Python实现点阵字体读取与转换的方法
2019/01/29 Python
pytorch 中的重要模块化接口nn.Module的使用
2020/04/02 Python
Python常用GUI框架原理解析汇总
2020/12/07 Python
css3 按钮样式简单可扩展创建
2013/03/18 HTML / CSS
css3 transform属性详解
2014/09/30 HTML / CSS
英国文胸专家:AmpleBosom.com
2018/02/06 全球购物
如何唤起类中的一个方法
2013/11/29 面试题
创新比赛获奖感言
2014/02/13 职场文书
求职信格式要求
2014/05/23 职场文书
维护民族团结演讲稿
2014/08/27 职场文书
ant design charts 获取后端接口数据展示
2022/05/25 Javascript
Oracle锁表解决方法的详细记录
2022/06/05 Oracle