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 相关文章推荐
select 控制网页内容隐藏于显示的实现代码
May 25 Javascript
firefox下frameset取不到值的解决方法
Sep 06 Javascript
js给页面加style无效果的解决方法
Jan 20 Javascript
JavaScript事件委托的技术原理探讨示例
Apr 17 Javascript
利用jQuery和CSS将背景图片拉伸
Oct 16 Javascript
addEventListener()与removeEventListener()解析
Apr 20 Javascript
使用nvm管理不同版本的node与npm的方法
Oct 31 Javascript
JavaScript设计模式之享元模式实例详解
Jan 17 Javascript
CKeditor富文本编辑器使用技巧之添加自定义插件的方法
Jun 14 Javascript
javascript跳转与返回和刷新页面的实例代码
Nov 20 Javascript
JavaScript装饰者模式原理与用法实例详解
Mar 09 Javascript
js获取url页面id,也就是最后的数字文件名
Sep 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
php中strstr、strrchr、substr、stristr四个函数的区别总结
2014/09/22 PHP
PHP大神的十大优良习惯
2016/09/14 PHP
ThinkPHP实现图片上传操作的方法详解
2017/05/08 PHP
php实现数组纵向转横向并过滤重复值的方法分析
2017/05/29 PHP
PHP PDOStatement::bindParam讲解
2019/01/30 PHP
PHP 实现文件压缩解压操作的方法
2019/06/14 PHP
往光标所在位置插入值的js代码
2013/09/22 Javascript
js自定义鼠标右键的实现原理及源码
2014/06/23 Javascript
Eclipse配置Javascript开发环境图文教程
2015/01/29 Javascript
JavaScript计时器示例分析
2015/02/05 Javascript
详解JavaScript中数组的相关知识
2015/07/29 Javascript
Vue2.0利用 v-model 实现组件props双向绑定的优美解决方案
2017/03/13 Javascript
AngularJS实现的锚点楼层跳转功能示例
2018/01/02 Javascript
关于vue-router的那些事儿
2018/05/23 Javascript
JQuery Ajax执行跨域请求数据的解决方案
2018/12/10 jQuery
VSCode 添加自定义注释的方法(附带红色警戒经典注释风格)
2020/08/27 Javascript
vue使用vue-quill-editor富文本编辑器且将图片上传到服务器的功能
2021/01/13 Vue.js
python3安装speech语音模块的方法
2018/12/24 Python
Python实现的栈、队列、文件目录遍历操作示例
2019/05/06 Python
python实现五子棋游戏
2019/06/18 Python
python字符串的index和find的区别详解
2020/06/20 Python
moosejaw旗下的户外商品促销网站:Mountain Steals
2017/02/27 全球购物
亚洲领先的设计购物网站:Pinkoi
2020/11/26 全球购物
经管应届生求职信
2013/11/17 职场文书
红领巾广播站广播稿
2014/02/01 职场文书
激情洋溢的毕业生就业求职信
2014/03/15 职场文书
关于中国梦的演讲稿
2014/04/23 职场文书
国家励志奖学金个人先进事迹材料
2014/05/04 职场文书
励志演讲稿500字
2014/08/21 职场文书
委托证明模板
2014/09/16 职场文书
个人股份转让协议书范本
2014/10/26 职场文书
2014年酒店工作总结与计划
2014/11/17 职场文书
三方协议书
2015/01/27 职场文书
在职人员跳槽求职信
2015/03/20 职场文书
python文本处理的方案(结巴分词并去除符号)
2021/05/26 Python
k8s部署redis cluster集群的实现
2021/06/24 Redis