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 相关文章推荐
Prototype Function对象 学习
Jul 12 Javascript
利用谷歌地图API获取点与点的距离的js代码
Oct 11 Javascript
js数字转换为float,取N位小数
Feb 08 Javascript
JavaScript中的对象的extensible属性介绍
Dec 30 Javascript
jQuery实现鼠标选文字发新浪微博的方法
Apr 02 Javascript
JS比较两个数值的大小实例
Nov 25 Javascript
Vue.js父与子组件之间传参示例
Feb 28 Javascript
React Native中Navigator的使用方法示例
Oct 13 Javascript
AngularJS日期格式化常见操作实例分析
May 17 Javascript
微信小程序页面上下滚动效果
Nov 18 Javascript
addEventListener()和removeEventListener()追加事件和删除追加事件
Dec 04 Javascript
js实现头像上传并且可预览提交
Dec 25 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
PHP 采集程序原理分析篇
2010/03/05 PHP
初识Laravel
2014/10/30 PHP
php实现的树形结构数据存取类实例
2014/11/29 PHP
php基础教程
2015/08/26 PHP
用js来刷新当前页面保留参数的具体实现
2013/12/23 Javascript
JavaScript实现判断图片是否加载完成的3种方法整理
2015/03/13 Javascript
jquery拖拽排序简单实现方法(效果增强版)
2016/02/16 Javascript
jquery.cookie.js实现用户登录保存密码功能的方法
2016/04/15 Javascript
JavaScript实现横线提示输入验证码随输入验证码输入消失的方法
2016/09/24 Javascript
JS动态给对象添加属性和值的实现方法
2016/10/21 Javascript
jQuery插件ajaxFileUpload使用详解
2017/01/10 Javascript
Angular中ng-repeat与ul li的多层嵌套重复问题
2017/07/24 Javascript
JS数组操作中的经典算法实例讲解
2017/07/26 Javascript
使用JS编写的随机抽取号码的小程序
2017/08/11 Javascript
利用纯js + transition动画实现移动端web轮播图详解
2017/09/10 Javascript
JavaScript的Proxy可以做哪些有意思的事儿
2019/06/15 Javascript
Vue脚手架编写试卷页面功能
2020/03/17 Javascript
vuex刷新后数据丢失的解决方法
2020/10/18 Javascript
[54:30]Liquid vs Newbee 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/16 DOTA
浅谈function(函数)中的动态参数
2017/04/30 Python
python虚拟环境的安装配置图文教程
2017/10/20 Python
python使用pandas实现数据分割实例代码
2018/01/25 Python
python模拟表单提交登录图书馆
2018/04/27 Python
通过python检测字符串的字母
2020/02/18 Python
python新手学习使用库
2020/06/11 Python
Python3 + Appium + 安卓模拟器实现APP自动化测试并生成测试报告
2021/01/27 Python
10个顶级Python实用库推荐
2021/03/04 Python
阿根廷在线宠物商店:Puppis
2018/03/23 全球购物
有多年工作经验的自我评价
2014/03/02 职场文书
学生抄作业检讨书(2篇)
2014/10/17 职场文书
2014年学校团委工作总结
2014/12/20 职场文书
幼儿园毕业典礼园长致辞
2015/07/29 职场文书
2019运动会广播加油稿汇总
2019/08/21 职场文书
Apache Linkis 中间件架构及快速安装步骤
2022/03/16 Servers
Win10/Win11 任务栏替换成经典样式
2022/04/19 数码科技