关于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 相关文章推荐
JS在IE和FireFox之间常用函数的区别小结
Mar 12 Javascript
jQuery Ajax()方法使用指南
Nov 19 Javascript
JavaScript实现级联菜单的方法
Jun 29 Javascript
JavaScript的History API使搜索引擎抓取AJAX内容
Dec 07 Javascript
基于BootStrap的Metronic框架实现页面链接收藏夹功能按钮移动收藏记录(使用Sortable进行拖动排序)
Aug 29 Javascript
禁用backspace网页回退功能的实现代码
Nov 15 Javascript
jQuery日期范围选择器附源码下载
May 23 jQuery
angular 实现同步验证器跨字段验证的方法
Apr 11 Javascript
vue 进阶之实现父子组件间的传值
Apr 26 Javascript
Vue中import from的来源及省略后缀与加载文件夹问题
Feb 09 Javascript
React组件设计模式之组合组件应用实例分析
Apr 29 Javascript
如何实现echarts markline标签名显示自己想要的
Jul 20 Javascript
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
第九节--绑定
2006/11/16 PHP
一些常用的php函数
2006/12/06 PHP
探讨方法的重写(覆载)详解
2013/06/08 PHP
PHP获取时间排除周六、周日的两个方法
2014/06/30 PHP
php判断是否连接上网络的方法实例详解
2016/12/14 PHP
Yii2.0多文件上传实例说明
2017/07/24 PHP
PHP随机数函数rand()与mt_rand()的讲解
2019/03/25 PHP
JavaScript进阶教程(第四课第一部分)
2007/04/05 Javascript
正则表达式判断是否存在中文和全角字符和判断包含中文字符串长度
2008/09/27 Javascript
jQuery对象和DOM对象相互转化
2009/04/24 Javascript
javascript 写类方式之二
2009/07/05 Javascript
juqery 学习之三 选择器 可见性 元素属性
2010/11/25 Javascript
收集json解析的四种方法分享
2014/01/17 Javascript
原生javascript实现拖动元素示例代码
2014/09/01 Javascript
JS+CSS实现可拖动的弹出提示框
2015/02/16 Javascript
JavaScript中window.open用法实例详解
2015/04/15 Javascript
Javascript通过overflow控制列表闭合与展开的方法
2015/05/15 Javascript
Bootstrap3 多个模态对话框无法显示的解决方案
2017/02/23 Javascript
js实现可以点击收缩或张开的悬浮窗
2017/09/18 Javascript
用p5.js制作烟花特效的示例代码
2018/03/21 Javascript
node.js学习笔记之koa框架和简单爬虫练习
2018/12/13 Javascript
JS闭包经典实例详解
2018/12/20 Javascript
基于vue的验证码组件的示例代码
2019/01/22 Javascript
在微信小程序中使用图表的方法示例
2019/04/25 Javascript
2019年度web前端面试题总结(主要为Vue面试题)
2020/01/12 Javascript
全面解析js中的原型,原型对象,原型链
2021/01/25 Javascript
[59:36]2018DOTA2亚洲邀请赛 4.3 突围赛 Secret vs VG 第二场
2018/04/04 DOTA
一个简单的python程序实例(通讯录)
2013/11/29 Python
python选择排序算法实例总结
2015/07/01 Python
python 实现tar文件压缩解压的实例详解
2017/08/20 Python
Python 找到列表中满足某些条件的元素方法
2018/06/26 Python
介绍一下如何优化MySql
2016/12/20 面试题
汽车专业毕业生自荐信
2013/11/03 职场文书
工厂门卫岗位职责
2013/11/25 职场文书
工程业务员岗位职责
2013/12/31 职场文书
新学期开学标语
2014/06/30 职场文书