关于JavaScript数组去重的一些理解汇总


Posted in Javascript onSeptember 10, 2020

前言

做前端开发几年,在项目中用到数组去重的机会倒不是很多,但是在面试的时候却经常被问到,个人理解,这道题真正考的是对JavaScript的基础的掌握,因为有很多种方式可以做到。这次就根据这道题,将相关的知识理解透彻。

一、ES6中的new Set方式

先看看MDN上对Set的描述:

Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。
Set对象是值的集合,你可以按照插入的顺序迭代它的元素。 Set中的元素只会出现一次,即 Set 中的元素是唯一的。

关键字:任何类型都可以存储、存储进来的值都是唯一的,这样就可以做到先把数组中重复的数据去掉。

const list1 = [1, 2, 3, 7, 11, 56, 3, 2, 4, 5]
const list2 = new Set(list1)
console.log(list2)

看一下返回的结果:

关于JavaScript数组去重的一些理解汇总

由结果可知,返回了一个可迭代的Set对象,此时还需要把Set对象转为数组。此时可以用到
Array.from()。

**Array.from()** 方法从一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例.

刚好new Set()返回的就是一个可迭代的对象。

const list3 = Array.from(new Set([null, null, undefined, 12, undefined, 7, 2, 1, 22, 2, function a(){}, function a(){}, {}, {}]))

结果是返回了一个数组:

关于JavaScript数组去重的一些理解汇总

这种方式不考虑兼容性,且去不掉重复的function和{}

关于Array.from()的扩展

Array.from(arrayLike[, mapFn[, thisArg]])

arrayLike: 伪数组和可迭代对象

mapFn:每个元素会执行这个回调方法

thisArg: 执行回调函数时this的指向。

const list4 = Array.from('name', arg => arg + 12)
console.log(list4) // [ 'n12', 'a12', 'm12', 'e12' ]

伪数组对象(拥有一个 length 属性和若干索引属性的任意对象, 如string)

可迭代对象(可以获取对象中的元素,如 Map和 Set 等)

二、set的另一种写法

const list20 = [5, 3, 5, 5, 6, 37, 22, 22]
console.log([...new Set(list20)])

其实跟第一种差不多

三、嵌套的for循环

const list5 = [null, null, undefined, undefined, {}, {}, function q() {}, function q() {}, 34, 2, 1, 2]
for(let i = 0; i < list3.length; i++) {
  for (let j = i + 1; j < list3.length; j++) {
    if (list3[i] === list3[j]) {
      list3.splice(j, 1) // 将重复的数据删掉一个
      j-- // 因为删除掉了一个元素,就从这个元素的索引重新开始
    }
  }
}

这种方式用了splice(index, num)的方法,返回的结果也没有把function和对象给去掉。我们能想到的最简单的方式就是这种去重方式。

四、indexOf方式

const list6 = [null, null, undefined, undefined, NaN, NaN, false, 'false', function a(){}, function a() {}, {}, {}]
const list7 = []
for(let k = 0; k<list6.length; k++) {
  if (list7.indexOf(list6[k]) === -1) {
    list7.push(list6[k])
  }
}
console.log(list7, 'list7') 
// [null, undefined,NaN, NaN,false,'false',[Function: a], [Function: a],{},{}] list7

关于indexOf

Array构造函数和String构造函数的原型上都有这个方法

MDN上对他们的解释分别是:

**indexOf()**方法返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。

arr.indexOf(searchElement[, fromIndex])

**indexOf()** 方法返回调用它的 String 对象中第一次出现的指定值的索引,从 fromIndex 处进行搜索。如果未找到该值,则返回 -1。

str.indexOf(searchValue [, fromIndex])

这么一看 就知道他俩用法一样。

五、sort

先看看关于sort的解释:

**sort()** 方法用原地算法对数组的元素进行排序,并返回数组。默认排序顺序是在将元素转换为字符串,然后比较它们的UTF-16代码单元值序列时构建的
由于它取决于具体实现,因此无法保证排序的时间和空间复杂性。

所以这种方式,在数组长的时候可能保证不了性能。用它去重的思路是什么呢?先用sort排序,然后前一个跟后一个比较,这样相同的值永远都是邻关系。

const list8 = [null, null, undefined, undefined, NaN, NaN, false, 'false', function a(){}, function a() {}, {}, {}]
const list9 = list8.sort()
const list10 = [list9[0]]
for(let i = 1; i<list9.length; i++) {
  if (list9[i] !== list9[i-1]) {
    list10.push(list9[i])
  }
}

这一看就很容易理解。

六、includes

const list11 = [null, null, undefined, undefined, NaN, NaN, false, 'false', function a(){}, function a() {}, {}, {}]
const list12 = []
for (let i = 0; i<list11.length ; i++) {
  if (!list12.includes(list11[i])) {
    list12.push(list11[i])
  }
}

此结果没有把function和{}去重,其他的都去重了。

includes也是Array构造函数和String构造函数上都有的方法。

七、filter和indexOf

// 数组去重方式6-filter和indexOf
const list13 = [1, 2, 3, 3, 5]
const list14 = list13.filter((item, index, arr) => {
  // 也就是在遍历这个数组list13的时候,每次拿当前的元素跟此数组中这个元素第一次出现的位置相比,如果位置是一致的,就返回当前元素
  return list13.indexOf(item, 0) === index
})

八、递归

const list15 = [1, 2, 3, 4, 5, 7, 6, 4, 3]
const list16 = list15
const len = list16.length
list16.sort(function(a, b) { return a - b }) // 先排序
function loop(index) {
  if (index >= 1) {
    if (list16[index] === list16[index - 1]) {
      list16.splice(index, 1)
    }
  loop(index - 1)
  }
}
loop(len - 1)

关于sort排序

在排序的时候 我们可能忽略了一个问题,可能得到的并不是我们想要的结果,比如下面的例子:

const list17 = [22, 1, 2, 15, 3, 4, 3, 1, 11]
console.log(list17.sort()) // [1, 1, 11, 15, 2, 22, 3, 3, 4]

看看得到的结果,根本就不是按照从小到大排的。这是因为:默认排序顺序是在将元素转换为字符串,然后比较它们的UTF-16代码单元值序列时构建的。
所以 要另找一种排序的方法,就是给sort传入一个函数。

arr.sort([compareFunction])

参数:

  • compareFunction: 可传可不传,传的话用来指定按某种顺序进行排列的函数。如果省略,元素按照转换为的字符串的各个字符的Unicode位点进行排序。
  • compareFunction的参数1-firstEl: 用于比较的第一个元素
  • compareFunction的参数2-secondEl: 用于比较的第二个元素
  • 如果 compareFunction(a, b) 小于 0 ,那么 a 会被排列到 b 之前;
  • 如果 compareFunction(a, b) 等于 0 , a 和 b 的相对位置不变。备注: ECMAScript 标准并不保证这一行为,而且也不是所有浏览器都会遵守(例如 Mozilla 在 2003 年之前的版本);
  • 如果 compareFunction(a, b) 大于 0 , b 会被排列到 a 之前。
  • compareFunction(a, b) 必须总是对相同的输入返回相同的比较结果,否则排序的结果将是不确定的。

返回值:

返回的是已经原地排序的数组。

九、用Map数据结构排序

const list 18 = [2, 3, 33, 2, 5, 1, 3]
const map1 = new Map()
for(let i = 0; i<list18.length; i++) {
  if (map1.get(list18[i])) {
    map1.set(list18[i], true)
  } else {
    map1.set(list18[i], false)
    list19.push(list18[i])
  }
}

这个比较好理解, 就不多说了。

总结

到此这篇关于关于JavaScript数组去重的一些理解的文章就介绍到这了,更多相关JavaScript数组去重内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
JavaScript 拾漏补遗
Dec 27 Javascript
checkbox设置复选框的只读效果不让用户勾选
Aug 12 Javascript
原生JavaScript实现连连看游戏(附源码)
Nov 05 Javascript
表单元素与非表单元素刷新区别详细解析
Nov 06 Javascript
Asp.Net alert弹出提示信息的几种方法总结
Jan 29 Javascript
Javascript让DEDECMS告别手写Tag
Sep 01 Javascript
解决同一页面中两个iframe互相调用jquery,js函数的方法
Dec 12 Javascript
js判断传入时间和当前时间大小实例(超简单)
Jan 11 Javascript
详解angular如何调用HTML字符串的方法
Jun 30 Javascript
vue.js项目 el-input 组件 监听回车键实现搜索功能示例
Aug 25 Javascript
详解vue2.0 资源文件assets和static的区别
Nov 27 Javascript
jquery+ajax实现异步上传文件显示进度条
Aug 17 jQuery
vue中jsonp插件的使用方法示例
Sep 10 #Javascript
vue 实现一个简单的全局调用弹窗案例
Sep 10 #Javascript
vue v-for 点击当前行,获取当前行数据及event当前事件对象的操作
Sep 10 #Javascript
vue 使用lodash实现对象数组深拷贝操作
Sep 10 #Javascript
Vue 按照创建时间和当前时间显示操作(刚刚,几小时前,几天前)
Sep 10 #Javascript
vue 导出文件,携带请求头token操作
Sep 10 #Javascript
vue radio单选框,获取当前项(每一项)的value值操作
Sep 10 #Javascript
You might like
PHP的单引号和双引号 字符串效率
2009/05/27 PHP
Thinkphp批量更新数据的方法汇总
2016/06/29 PHP
thinkphp 字母函数详解T/I/N/D/M/A/R/U
2017/04/03 PHP
基于swoole实现多人聊天室
2018/06/14 PHP
关于js日期转化为毫秒数“节省20%的效率和和节省9个字符“问题
2012/03/01 Javascript
Javascript图像处理—亮度对比度应用案例
2013/01/03 Javascript
JavaScript验证Email(3种方法)
2015/09/21 Javascript
利用js的闭包原理做对象封装及调用方法
2017/04/07 Javascript
基于jquery日历价格、库存等设置插件
2020/07/05 jQuery
jQuery.Form实现Ajax上传文件同时设置headers的方法
2017/06/26 jQuery
JS实现简单短信验证码界面
2017/08/07 Javascript
nuxt框架中路由鉴权之Koa和Session的用法
2018/05/09 Javascript
JS原生瀑布流效果实现
2019/04/26 Javascript
js实现简单的日历显示效果函数示例
2019/11/25 Javascript
vue中touch和click共存的解决方式
2020/07/28 Javascript
[02:35]DOTA2超级联赛专访XB 难忘一年九冠称王
2013/06/20 DOTA
[20:21]《一刀刀一天》第十六期:TI国际邀请赛正式打响,总奖金超过550万
2014/05/23 DOTA
[10:24]郎朗助力完美“圣”典,天籁交织奏响序曲
2016/12/18 DOTA
[01:47]2018年度DOTA2最具人气解说-完美盛典
2018/12/16 DOTA
python 获取本机ip地址的两个方法
2013/02/25 Python
python实现从字典中删除元素的方法
2015/05/04 Python
查看django执行的sql语句及消耗时间的两种方法
2018/05/29 Python
python 五子棋如何获得鼠标点击坐标
2019/11/04 Python
Python文件读写w+和r+区别解析
2020/03/26 Python
Python调用C语言程序方法解析
2020/07/07 Python
使用Html5、CSS实现文字阴影效果
2018/01/17 HTML / CSS
全球知名提供各类营养保健品的零售商:Vitamin Shoppe
2016/10/09 全球购物
猫咪家具:CatsPlay
2018/11/03 全球购物
法国包包和行李箱销售网站:Bagage24.fr
2020/03/24 全球购物
青春演讲稿范文
2014/05/08 职场文书
老人节主持词
2015/07/04 职场文书
网络研修心得体会
2016/01/08 职场文书
Django debug为True时,css加载失败的解决方案
2021/04/24 Python
Python办公自动化之教你如何用Python将任意文件转为PDF格式
2021/06/28 Python
分享五个Node.js开发的优秀实践 
2022/04/07 NodeJs
Nginx跨域问题解析与解决
2022/08/05 Servers