关于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 相关文章推荐
新浪刚打开页面出来的全屏广告代码
Apr 02 Javascript
js 获取浏览器高度和宽度值(多浏览器)
Sep 02 Javascript
解决jquery异步按一定的时间间隔刷新问题
Dec 10 Javascript
客户端js判断文件类型和文件大小即限制上传大小
Nov 20 Javascript
JavaScript设计模式之抽象工厂模式介绍
Dec 28 Javascript
JavaSciprt中处理字符串之sup()方法的使用教程
Jun 08 Javascript
简介JavaScript中的unshift()方法的使用
Jun 09 Javascript
深入理解JavaScript函数参数(推荐)
Jul 26 Javascript
JavaScript的setter与getter方法
Nov 29 Javascript
vue2.0 常用的 UI 库实例讲解
Dec 12 Javascript
Node快速切换版本、版本回退(降级)、版本更新(升级)
Jan 07 Javascript
ReactRouter的实现方法
Jan 25 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
php用header函数实现301跳转代码实例
2013/11/25 PHP
php微信公众开发之获取周边酒店信息的方法
2014/12/22 PHP
PDO::prepare讲解
2019/01/29 PHP
PHP getNamespaces()函数讲解
2019/02/03 PHP
php判断某个方法是否存在函数function_exists (),method_exists()与is_callable()区别与用法解析
2020/04/20 PHP
PhpStorm 2020.3:新增开箱即用的PHP 8属性(推荐)
2020/10/30 PHP
Add a Formatted Table to a Word Document
2007/06/15 Javascript
原生js结合html5制作简易的双色子游戏
2015/03/30 Javascript
JavaScript实现页面5秒后自动跳转的方法
2015/04/16 Javascript
JavaScript中的函数嵌套使用
2015/06/04 Javascript
浅析JS原型继承与类的继承
2016/04/07 Javascript
D3.js实现直方图的方法详解
2016/09/25 Javascript
Bootstrap 3.x打印预览背景色与文字显示异常的解决
2016/11/06 Javascript
jQuery实现动态添加tr到table的方法
2016/12/26 Javascript
浅谈FastClick 填坑及源码解析
2018/03/02 Javascript
node实现生成带参数的小程序二维码并保存到本地功能示例
2018/12/05 Javascript
使用Angular自定义字段校验指令的方法示例
2019/02/01 Javascript
JS实现简单贪吃蛇小游戏
2020/10/28 Javascript
[01:05:07]DOTA2-DPC中国联赛 正赛 DLG vs Dragon BO3 第一场2月1日
2021/03/11 DOTA
Python常见数据结构详解
2014/07/24 Python
简单介绍Python的Django框架加载模版的方式
2015/07/20 Python
Flask框架各种常见装饰器示例
2018/07/17 Python
解决django前后端分离csrf验证的问题
2019/02/03 Python
numpy中的meshgrid函数的使用
2019/07/31 Python
python检测服务器端口代码实例
2019/08/31 Python
pytorch: Parameter 的数据结构实例
2019/12/31 Python
python中如何使用insert函数
2020/01/09 Python
Python如何使用turtle库绘制图形
2020/02/26 Python
解决Python 异常TypeError: cannot concatenate 'str' and 'int' objects
2020/04/08 Python
Tensorflow中的降维函数tf.reduce_*使用总结
2020/04/20 Python
Sublime Text3最新激活注册码分享适用2020最新版 亲测可用
2020/11/12 Python
python 如何把docker-compose.yaml导入到数据库相关条目里
2021/01/15 Python
JS原生实现轮播图的几种方法
2021/03/23 Javascript
爱之链教学反思
2014/04/30 职场文书
创先争优一句话承诺
2014/05/29 职场文书
升职自荐书
2019/05/09 职场文书