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中创建实例与原型继承揭秘
Dec 21 Javascript
JQuery中使用Ajax赋值给全局变量失败异常的解决方法
Aug 18 Javascript
jQuery实现倒计时按钮功能代码分享
Sep 03 Javascript
超炫的jquery仿flash导航栏特效
Nov 11 Javascript
JS原型、原型链深入理解
Feb 27 Javascript
js实现商品抛物线加入购物车特效
Nov 18 Javascript
BootStrap智能表单实战系列(九)表单图片上传的支持
Jun 13 Javascript
CSS3 media queries结合jQuery实现响应式导航
Sep 30 Javascript
防止重复发送 Ajax 请求
Feb 15 Javascript
详解wepy开发小程序踩过的坑(小结)
May 22 Javascript
关于JSON解析的实现过程解析
Oct 08 Javascript
JS如何定义用字符串拼接的变量
Jul 11 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/03/27 PHP
详解php的魔术方法__get()和__set()使用介绍
2012/09/19 PHP
php随机输出名人名言的代码
2012/10/07 PHP
PHP微信API接口类
2016/08/22 PHP
PHP实现的简单适配器模式示例
2017/06/22 PHP
js 页面关闭前的出现提示的实现代码
2011/05/25 Javascript
EasyUI 中 MenuButton 的使用方法
2012/07/14 Javascript
转义字符(\)对JavaScript中JSON.parse的影响概述
2013/07/17 Javascript
js获取控件位置以及不同浏览器中的差别介绍
2013/08/08 Javascript
浅析Cookie中的Path与domain
2013/12/18 Javascript
网站接入QQ登录的两种方法
2014/07/22 Javascript
深入探讨javascript函数式编程
2015/10/11 Javascript
基于jquery实现百度新闻导航菜单滑动动画
2016/03/15 Javascript
JS仿百度自动下拉框模糊匹配提示
2016/07/25 Javascript
AngularJS入门教程之Scope(作用域)
2016/07/27 Javascript
jQuery Dialog 取消右上角删除按钮事件
2016/09/07 Javascript
详解Vue学习笔记进阶篇之列表过渡及其他
2017/07/17 Javascript
浅谈Javascript中的对象和继承
2019/04/19 Javascript
javascript实现倒计时效果
2020/02/17 Javascript
vant 时间选择器--开始时间和结束时间实例
2020/11/04 Javascript
Python牛刀小试密码爆破
2011/02/03 Python
Python中input与raw_input 之间的比较
2017/08/20 Python
解决matplotlib库show()方法不显示图片的问题
2018/05/24 Python
python实现桌面托盘气泡提示
2019/07/29 Python
python字符串替换re.sub()方法解析
2019/09/18 Python
eharmony澳大利亚:网上约会服务
2020/02/29 全球购物
一道写SQL的面试题和答案
2013/11/19 面试题
毕业生的自我评价范文
2013/12/31 职场文书
cf收人广告词大全
2014/03/14 职场文书
违章停车检讨书
2014/10/21 职场文书
员工2014年度工作总结
2014/12/09 职场文书
教师年度考核个人总结
2015/02/12 职场文书
2015年党风廉政建设工作总结
2015/04/09 职场文书
离婚承诺书格式范文
2015/05/04 职场文书
职工培训工作总结
2015/08/10 职场文书
《勇者辞职不干了》上卷BD发售宣传CM公开
2022/04/08 日漫