JavaScript数组去重的几种方法


Posted in Javascript onApril 07, 2019

前言

有时候我们做项目的时候往往会需要把数组里面一些重复的项去掉,但是原生JS有排序,有筛选等等,但是就是没有数组去重怎么办呢?

这能怎么办,自己手动实现嘛。

数组不像对象和hash有唯一的标志特征(key)。所以,数组去重的核心就是【1】数组内元素互相比较,然后放入新的数组中。【2】参照对象构建一个唯一的特征标志,然后放入新数组中。以下就是依照这种思路产生的方法。【3】数组中含对象的去重方式我采用使用JSON.stringify()将对象转换成JSON字符串进行比较的方式。

1.最基础的去重:双重遍历

双重遍历的核心就是依据【1】,通过拿出一个元素和剩下的元素依次比较,如果全部不相等则证明此元素为唯一。

let a=[{a:1},{b:2},{c:3},{a:1},{d:2}]
let c=[1,2,3,4,5,6,1,2,3]
function unique(arr){
 let b=[]
 for(let i=0;i<arr.length;i++){
 let unexit=true
 for(let j=i+1;j<arr.length;j++){
  if(JSON.stringify(arr[i])===JSON.stringify(arr[j])){
  unexit=false
  break
  }
  else{
  unexit=true
  }
 }
 if(unexit){
  b.push(arr[i])
 }
 }
 return b
}

关于数组中存在对象,是采用JSON.stringify()转换成JSON字符串进行的比较,后续不再叙述。双重遍历的缺点是复杂度太高。
上面的代码去重得到的结果的顺序会改变,所以如果想要顺序按照原有顺序,数组在进行去重时建议重新申明一个新的数组(var new=old.reverse() )得到一个新的相反的数组,最后再使用reverse()。之所以新建数组而不是直接取反是因为:reverse()会修改原数组。

2.Array.prototype.sort():相邻元素去重

相邻元素去重的核心在于Array.sort()能够对数组进行排序。这样相等的数组就会在相邻的位置,通过比较相邻的元素就可以起到去重的作用【1】。

let c=[1,2,3,4,5,6,1,2,3]
function unique(arr){
 let Arr=arr.sort()
 let b=[]
 for(let i=0;i<Arr.length;i++){
 if(Arr[i]!==Arr[i+1]){
  b.push(Arr[i])
 }
 }
 return b
}

Array.prototype.sort()方法可以使用array.sort((a,b)=>{a.key-b.ky})进行对象的排序,前提是数组中的对象存在相同的key值。

3.Object.keys():存在唯一性

在一个对象里面key值是唯一的,所以通过遍历数组给每个数组一个标志,通过标志去重【2】

let a=[{a:1},{b:2},{c:3},{a:1},{d:2}]
let c=[1,2,3,4,5,6,1,2,3]
function unique(arr){
 let b=[]
 let hash={}
 for(let i=0;i<arr.length;i++){
 if(!hash[JSON.stringify(arr[i])]){
  hash[JSON.stringify(arr[i])]=true
  b.push(arr[i])
 }
 }
 return b
}

4.双重遍历去重改良之:indexOf

双重遍历的思路我们都知道,先拿出一个元素,然后使用循环再次遍历数组去一一比较。如果有一个方式能够让我们不再遍历一遍数组,那么复杂度相对而言会减少一点。

indexOf 方法返回给定元素在数组中第一次出现的位置,如果没有出现则返回-1。首先我们新建一个空数组(arry),如果:arry.indexOf(数组元素)===-1,那么我们就可以知道arry中不存在元素。

let c=[1,2,3,4,5,6,1,2,3]
function unique(arr){
 let b=[]
 for(let i=0;i<arr.length;i++){
 if(b.indexOf(arr[i])==-1){
  b.push(arr[i])
 }
 }
 return b
}

indexOf 方法可返回某个指定的字符串值在字符串中首次出现的位置。所以对象不适用,因为对象转为字符串就都会变成{object,object} ,无法比较。

5.循环遍历之:map()/forEach()

map()和forEach()都可以实现遍历数组。所以以上的方法都可以用map()、forEach()改写。下面我只简单的改写一个,其他的改写方式参照即可。

let c=[1,2,3,4,5,6,1,2,3]
function unique(arr){
 let b=[]
 arr.forEach(res=>{
 if(b.indexOf(res)==-1){
  b.push(res)
 }
 })
 return b
}

6.ES6:Set数据结构

Set数据类似于数组,但是成员的值都是唯一的,没有重复的值。它可以接收一个数组,类于:let a=[1,2,3,1,2]  Set(a)=>1,2,3 所以可以使用Set()实现去重。

let c=[1,2,3,4,5,6,1,2,3]
function unique(arr){
 let b=new Set(arr)
 let c=Array.from(b)
 return c
}

Set去重不适用于含对象的数组,因为Set的去重参照的是(===),数组中的元素对象,虽然可能数值相等,但是地址不相等。所以Set无法实现去重。

7.总结

实现数组的去重,要么通过元素对比,要么设置特殊标志识别。元素对比的思路有2种:一种是和原数组一一对比;另一种和新的数组对比。

如果要实现含对象的数组去重,一般使用遍历的方式,包括使用遍历类的方法(map、forEach、reduce等)。像Set、sort等通过改变数组的方式一般是不可行的。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
IE 缓存策略的BUG的解决方法
Jul 21 Javascript
Dom 结点创建 基础知识
Oct 01 Javascript
JavaScript NaN和Infinity特殊值 [译]
Sep 20 Javascript
常规表格多表头查询示例
Feb 21 Javascript
使用vue.js开发时一些注意事项
Apr 27 Javascript
js实现纯前端的图片预览
Apr 27 Javascript
快速移动鼠标触发问题及解决方法(ECharts外部调用保存为图片操作及工作流接线mouseenter和mouseleave)
Aug 29 Javascript
js的三种继承方式详解
Jan 21 Javascript
用vue的双向绑定简单实现一个todo-list的示例代码
Aug 03 Javascript
javascript深拷贝、浅拷贝和循环引用深入理解
May 27 Javascript
Bootstrap 时间日历插件bootstrap-datetimepicker配置与应用小结
May 28 Javascript
为什么推荐使用JSX开发Vue3
Dec 28 Vue.js
vue表单验证你真的会了吗?vue表单验证(form)validate
Apr 07 #Javascript
js中Generator函数的深入讲解
Apr 07 #Javascript
巧妙运用v-model实现父子组件传值的方法示例
Apr 07 #Javascript
vue路由导航守卫和请求拦截以及基于node的token认证的方法
Apr 07 #Javascript
vue自定义指令directive的使用方法
Apr 07 #Javascript
浅谈express.js框架中间件(middleware)
Apr 07 #Javascript
详解vue中this.$emit()的返回值是什么
Apr 07 #Javascript
You might like
PHP设计模式之命令模式的深入解析
2013/06/13 PHP
php实现根据字符串生成对应数组的方法
2014/09/22 PHP
使用PHP连接多种数据库的实现代码(mysql,access,sqlserver,Oracle)
2016/12/21 PHP
基于jquery.Jcrop的头像编辑器
2010/03/01 Javascript
jQuery MD5加密实现代码
2010/03/15 Javascript
判断浏览器的javascript版本的代码
2010/09/03 Javascript
最新的10款jQuery内容滑块插件分享
2011/09/18 Javascript
js浮点数精确计算(加、减、乘、除)
2013/12/26 Javascript
js出生日期 年月日级联菜单示例代码
2014/01/10 Javascript
跟我学习javascript的浮点数精度
2015/11/16 Javascript
基于JavaScript实现动态创建表格和增加表格行数
2015/12/20 Javascript
你不知道的高性能JAVASCRIPT
2016/01/18 Javascript
JQuery核心函数是什么及使用方法介绍
2016/05/03 Javascript
jquery实现的回旋滚动效果完整实例【附demo源码下载】
2016/09/20 Javascript
node.js Sequelize实现单实例字段或批量自增、自减
2016/12/08 Javascript
微信小程序实现image组件图片自适应宽度比例显示的方法
2018/01/16 Javascript
详解vue添加删除元素的方法
2018/06/30 Javascript
Vue用v-for给循环标签自身属性添加属性值的方法
2018/10/18 Javascript
vue刷新页面时去闪烁提升用户体验效果的实现方法
2018/12/10 Javascript
JavaScript实现图片上传并预览并提交ajax
2019/09/30 Javascript
javascript实现滚动条效果
2020/03/24 Javascript
如何利用JavaScript编写更好的条件语句详解
2020/08/10 Javascript
[59:42]Secret vs Alliacne 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/17 DOTA
Python代码的打包与发布详解
2014/07/30 Python
Python类的专用方法实例分析
2015/01/09 Python
简单谈谈python中的多进程
2016/11/06 Python
利用信号如何监控Django模型对象字段值的变化详解
2017/11/27 Python
Python 获取 datax 执行结果保存到数据库的方法
2019/07/11 Python
英国家电直销:Appliances Direct
2016/09/22 全球购物
银行职员思想汇报
2013/12/31 职场文书
老公给老婆的道歉信
2014/01/10 职场文书
机房搬迁方案
2014/05/01 职场文书
学校政风行风自查自纠报告
2014/10/21 职场文书
开业典礼致辞
2015/07/29 职场文书
2022新作动画《福星小子》释出宣传影片 加入内田真礼&宫野真守配音演出
2022/04/08 日漫
python中Pyqt5使用Qlabel标签播放视频
2022/04/22 Python