浅理解JavaScript数组去重的方法(划重点),当面试官问如何实现数组去重时,你可以这样做...

文章目录

  • 📋前言
  • 🎯什么是数组去重,运用场景是什么?
  • 🎯常用的数组去重方法
    • 🧩使用 Set 对象
    • 🧩使用 Object(对象、基于Hash哈希表) 或 Map
    • 🧩使用 filter 方法与 indexOf 方法
  • 🎯其他方法
    • 🧩使用 reduce 方法
    • 🧩使用递归方法
    • 🧩使用 ES6 中的 Symbol 数据类型
    • 🧩使用 hasOwnProperty 方法
    • 🧩使用 lodash 库
  • 📝最后


在这里插入图片描述

📋前言

好久没写面试题的文章了,今天这篇文章讲一讲一个常见的面试题。在前端开发岗位的面试过程中,我们可能或多或少会提及数组这个知识点,对于数组的相关操作也是一个经常提及的技术点,其中数组去重是面试中非常常见的一个问题,无论是手写还是口述,我们都要有清晰的逻辑和思路去面对这个问题,因此这篇文章我们来浅理解在JavaScript中如何实现数组去重,让你在面试无压力回答面试官。


🎯什么是数组去重,运用场景是什么?

数组去重就是将一个数组中重复的元素去掉,只保留一个或不保留。在实际开发中,数组去重非常重要,它可以提高代码执行效率,减少内存开销,并且使数据更加规范化和易于处理。这个过程可以使用多种方法来实现,具体取决于需求和场景。

在实际开发中,数组去重常常用于以下场景:

  • 数据展示
    • 在一些数据展示的场景中,我们通常需要从后台获取到一个数组类型的数据,并将其渲染到页面上。如果数组中存在重复项,则会影响数据的展示效果。因此,我们通常需要在渲染之前使用数组去重方法对数据进行处理,以提高数据展示的质量和效率。
  • 数据统计
    • 在进行数据统计时,通常需要对数组中的元素进行去重操作,以减少重复计算,提高计算效率。例如,在进行 UV 统计时,我们需要对访客 IP 进行去重操作,以得到准确的 UV 计数结果。
    • ❗补充:UV 是 Unique Visitor(独立访客)的简称,指访问某个网站或页面的不同访客数量。UV 统计是对网站访问情况进行统计的一种方法,用于分析网站流量、用户行为等数据。
  • 表单验证
    • 在表单验证过程中,我们需要对用户输入的内容进行校验,避免用户重复提交相同的内容,这时候我们就需要对表单数据进行去重操作,以提高表单验证的准确性和稳定性。

🎯常用的数组去重方法

在实际开发中,为了提高代码执行效率和减少内存开销,我们通常采用以下几种数组去重方法。

🧩使用 Set 对象

Set 是 ES6 新增的内置对象,可以用来存储无重复值的集合。我们可以将数组转换为 Set,然后再将 Set 转换回数组即可。Set 对象的一个优点是可以快速地去除数组中的重复项。

const arr = [1, 2, 3, 3, 4, 5, 5];
const newArr = [...new Set(arr)];
console.log(newArr); // [1, 2, 3, 4, 5]

除了使用ES6中的扩展运算符加Set来实现数组去重,还可以利用 ES6 中的 from 方法。利用 ES6 中的 from 方法和 Set 数据结构,将数组转换成 Set 数据结构,再将 Set 数据结构转换回数组。

const arr = [1, 2, 3, 3, 4, 5, 5];
const newArr = Array.from(new Set(arr));
console.log(newArr); // [1, 2, 3, 4, 5]

在这里插入图片描述

❗ 补充
下面这段代码是实际开发中数组去重的一个案例,这段代码的作用是,把用户输入的新词条添加到历史记录的数组中,然后通过 Set 来对这个数组进行去重操作,确保渲染出来的搜索历史记录没有重复显示。
在这里插入图片描述

🧩使用 Object(对象、基于Hash哈希表) 或 Map

利用 Map 数据结构,遍历数组,返回一个新的数组,该数组中只包含不与前面元素重复的元素。

let arr = [1, 2, 3, 3, 4, 4, 5];
let newArr = [];
let map = new Map();
for(let i = 0; i < arr.length; i++){
    if(!map.has(arr[i])){
        map.set(arr[i], true);
        newArr.push(arr[i]);
    }
}
console.log(newArr); // [1, 2, 3, 4, 5]

这种方法跟使用对象实现的去重方法相似,只不过用的是 ES6 中新增的 Map 数据结构。Map 对象保存键值对,并且能够记住键的原始插入顺序。所以通过遍历数组将每个元素作为键存储在 Map 中,如果该元素不存在,则说明它是新的元素,此时将它添加到新建的数组 newArr 中,并在 Map 中将其添加为键。最后输出 newArr 数组即可。

接下来看看使用对象实现的去重方法。

1️⃣基于 Hash 表实现,首先创建一个空对象,遍历数组,将数组元素作为对象的键值,如果该键不存在,则添加键值对,否则不做操作。最后将对象中的所有键转换成数组即可。

let arr = [1, 2, 3, 3, 4, 4, 5];
let obj = {};
for(let i = 0; i < arr.length; i++){
    let value = arr[i];
    obj[value] = true;
}
let newArr = Object.keys(obj).map(function(item){
    return Number(item);
});
console.log(newArr); // [1, 2, 3, 4, 5]

它的原理是利用 JavaScript 中对象的属性唯一性,将数组中的元素作为对象的属性名,把属性值都设为 true(或任意其他值),然后再利用 Object.keys 方法获取对象的所有属性名(即数组中的不同元素),最后再利用 map 方法将属性名转换为数字类型即可。(需要注意的一点是,由于对象的属性名必须是字符串类型,因此在后续的操作中可以将它们转换为数字类型,但这并不影响数组去重的结果。)

2️⃣定义一个空对象 obj 和一个空数组 newArr。遍历原始数组 arr,对于每一个元素,执行以下操作: a. 判断 obj 中是否存在该元素,如果不存在,则将其加入 obj,并将其加入 newArr; b. 如果已经存在,则不做任何操作。遍历完所有元素后,newArr 中就存储了去重后的结果,即为 arr 去重之后的新数组。

const arr = [1, 2, 3, 3, 4, 5, 5];
const obj = {};
const newArr = [];
for(let i = 0; i < arr.length; i++) {
  if(!obj[arr[i]]) {
    obj[arr[i]] = true;
    newArr.push(arr[i]);
  }
}
console.log(newArr); // [1, 2, 3, 4, 5]

在这里插入图片描述

📌总结

  • 基于 Hash 表的方法仅适用于数组中元素都是基本数据类型的情况,对于包含引用类型的数组,需要使用其他方法实现去重。此外,由于 obj 对象的存在,使用这种方法会占用额外的内存空间,因此在大规模数据处理时需要考虑性能问题。
  • 相比较于基于 Hash 表的方法,使用 Map 的方法避免了对象 key 会被隐式转换成字符串的问题,同时也更加简洁明了。在大规模数据处理时,它的性能也有很好的表现。(需要注意的是,Map 是 ES6 中新增的数据结构,如果要在低版本浏览器中使用,需要进行兼容处理。)

🧩使用 filter 方法与 indexOf 方法

通过 filter 方法和 indexOf 方法来实现数组去重。对于数组中的每个元素,只保留第一个出现的元素,其他的重复元素通过 filter 方法过滤掉。

const arr = [1, 2, 3, 3, 4, 5, 5];
const newArr = arr.filter((item, index) => {
  return arr.indexOf(item) === index;
});
console.log(newArr); // [1, 2, 3, 4, 5]

不使用 filter 的情况下,只使用 indexOf 方法进行去重,可以通过遍历原数组 arr,对于每个元素,判断它在数组中第一次出现的位置是否等于当前位置。如果相等,则说明它是第一次出现,将其添加到新建的数组 newArr 中即可。

let arr = [1, 2, 3, 3, 4, 4, 5];
let newArr = [];
for(let i = 0; i < arr.length; i++){
    if(arr.indexOf(arr[i]) === i){
        newArr.push(arr[i]);
    }
}
console.log(newArr); // [1, 2, 3, 4, 5]

❗ 补充:与 indexOf 方法类似,可以用 includes 方法进行数组去重的操作,逻辑思路也非常相似,区别在于这两个方法的实质区别。

includes() 方法是 ES7 引入的新方法,该方法判断一个数组是否包含一个指定的值,如果是,则返回 true;否则,返回 false。需要注意的是,includes() 方法是区分基本数据类型和引用数据类型的,也就是说,对于引用数据类型,它们的地址不同即使它们所存储的值相同,也会被认为是不同的元素。另外,includes() 方法不返回符合条件的元素的下标,而是直接返回一个布尔值。

indexOf() 方法是 JavaScript中常用的数组方法,用于返回指定元素在数组中第一次出现的位置。与 includes() 方法不同,indexOf() 方法返回符合条件的元素的下标位置,如果没有找到,则返回 -1。

includes() 方法只接受一个参数,即要查找的元素;而 indexOf() 方法可以接受两个参数,第一个参数为要查找的元素,第二个参数为起始搜索位置的索引值。

let arr = [1, 2, 3, 3, 4, 4, 5];
let newArr = [];
for(let i = 0; i < arr.length; i++){
    if(!newArr.includes(arr[i])){
        newArr.push(arr[i]);
    }
}
console.log(newArr); // [1, 2, 3, 4, 5]

在这里插入图片描述


🎯其他方法

除了上述的这些较为常用的方法,数组去重的方法还有很多,这里就不详细介绍了,接下来简单介绍几个。

🧩使用 reduce 方法

利用数组的 reduce 方法,遍历数组,使用一个变量保存上一个已经出现过的元素,并将当前元素与该变量进行比较,若不相同则加入新的数组中。

1️⃣使用indexOf()

let arr = [1, 2, 3, 3, 4, 4, 5];
let newArr = arr.reduce((item, index) => {
    if(item.indexOf(index)===-1){
        item.push(index);
    }
    return item;
}, []);
console.log(newArr); // [1, 2, 3, 4, 5]

2️⃣使用includes()

let arr = [1, 2, 3, 3, 4, 4, 5];
let newArr = arr.reduce((item, index) => {
    if(!item.includes(index)){
        item.push(index);
    }
    return item;
}, []);
console.log(newArr); // [1, 2, 3, 4, 5]

🧩使用递归方法

递归地遍历数组并将出现在前面的元素和后面出现的相同元素删除掉。

let arr = [1, 2, 3, 3, 4, 4, 5];
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--;
        }
    }
}
console.log(arr); // [1, 2, 3, 4, 5]

🧩使用 ES6 中的 Symbol 数据类型

创建一个空对象,遍历数组,将数组元素作为对象的键值,由于 Symbol 值在对象属性名上是唯一的,因此如果该键不存在,则添加该键,否则不做操作。最后将所有键转换成数组即可。

let arr = [1, 2, 3, 3, 4, 4, 5];
let obj = {};
for(let i = 0; i < arr.length; i++){
    let value = arr[i];
    obj[Symbol.for(value)] = value;
}
let newArr = Object.getOwnPropertySymbols(obj).map(function(sym){
    return obj[sym];
});
console.log(newArr); // [1, 2, 3, 4, 5]

🧩使用 hasOwnProperty 方法

利用 Object 对象的 hasOwnProperty 方法,利用其属性名唯一特性,遍历数组,返回一个新的数组,该数组中只包含不与前面元素重复的元素。

let arr = [1, 2, 3, 3, 4, 4, 5];
let newArr = [];
let obj = {};
for(let i = 0; i < arr.length; i++){
    if(!obj.hasOwnProperty(arr[i])){
        obj[arr[i]] = true;
        newArr.push(arr[i]);
    }
}
console.log(newArr); // [1, 2, 3, 4, 5]

🧩使用 lodash 库

lodash 库是一个 JavaScript 的实用工具库,其中包含了大量的常用函数。使用 lodash 库的 uniq 函数即可实现数组去重。

import { uniq } from 'lodash';

let arr = [1, 2, 3, 3, 4, 4, 5];
let newArr = uniq(arr);
console.log(newArr); // [1, 2, 3, 4, 5]

📝最后

在开发中,数组去重非常重要,它可以提高代码执行效率,减少内存开销,并且使数据更加规范化和易于处理。数组去重的方法有很多,我们要具体问题具体分析,可以选择根据具体场景和需求,选用最适合的去重方法,多方面考虑,比如说考虑这个方法的时间复杂度、数组大小、数组是否要过滤、排序等等问题。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/13340.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Smartbi电子表格软件架构与差异化特色

Smartbi电子表格软件选择与Excel结合&#xff0c;原因在于Excel一直被模仿&#xff0c;从未被超越。虽然市场上的报表软件很多&#xff0c;但存在太多的不完美。国外的产品功能复杂、难于学习&#xff08;控件方式&#xff09;&#xff0c;做不了中国式复杂格式的报表&#xff…

Python双向循环链表的操作

目录 一、双向循环链表 双向循环链表图 二、双向循环链表的操作 1、判断链表是否为空 2&#xff0c;链表长度 3&#xff0c;遍历整个链表 4&#xff0c;在链表头部添加元素 5、链表尾部添加元素 6&#xff0c;在指定位置插入元素 7&#xff0c;修改指定位置的元素 8&a…

VS Code 插件开发概览

VS Code 插件开发概览 前言 VS Code作为开发者的代码开发利器&#xff0c;越来越受开发者的喜爱。像我身边的前端&#xff0c;每天80%的开发工作都是在VS Code上完成的。随着人们对它的使用&#xff0c;不再满足简单的优雅&#xff0c;舒服写代码这一基本需求。有些人利用它进…

阿里ARouter 路由框架解析

一、简介 众所周知&#xff0c;在日常开发中&#xff0c;随着项目业务越来越复杂&#xff0c;项目中的代码量也越来越多&#xff0c;如果维护、扩展、解耦等成了一个非常头疼问题&#xff0c;随之孕育而生的诸如插件化、组件化、模块化等热门技术。 而其中组件化中一项的难点&…

深入理解Linux多线程

致前行的人&#xff1a; 昨日渐多&#xff0c;明日愈少&#xff0c;今日还在&#xff0c;不要为成功而努力&#xff0c;要为做一个有价值的人而努力。人生道路上充满了坎坷&#xff0c;谁也不可能一帆风顺。只有在最困难的时刻&#xff0c;才能体会到无助的含义。 目录 1.理解…

SpringBoot集成MyBatis-yml自动化配置原理详解

SpringBoot集成MyBatis-yml自动化配置原理详解 简介&#xff1a;spring boot整合mybatis开发web系统目前来说是市面上主流的框架&#xff0c;每个Java程序和springboot mybatis相处的时间可谓是比和自己女朋友相处的时间都多&#xff0c;但是springboot mybatis并没有得到你的真…

适用于 Windows 的 5 个最好的 PDF 转换器应用程序

由于稳定性、高分辨率、高安全性、易于传输等特点&#xff0c;PDF已经成为我们日常工作中最常用的格式。我们在享受PDF带来便利的同时&#xff0c;也发现PDF带来了一些不便&#xff0c;其中最大的问题就是PDF内容的编辑难度。同时&#xff0c;并不是所有的文件都是PDF格式的&am…

代码优化- 前端优化

常量折叠 基本思想&#xff1a;在编译期间计算表达式的值&#xff08;编译时静态计算&#xff09; 例如&#xff1a;a 3 5 > a 8&#xff0c;if (true && false) ... > if (false) 好处是&#xff1a;语法树的节点数量减少了&#xff0c;意味着编译器要维护…

Ubuntu上跑通PaddleOCR

书接上文。刚才说到我已经在NUC8里灌上了Windows Server 2019。接下来也顺利的启用了Hyper-V角色并装好了一台Ubuntu 22.04 LTS 的虚机。由于自从上回在树莓派上跑通了Paddle-Lite-Demo之后想再研究一下PaddleOCR但进展不顺&#xff0c;因此决定先不折腾了&#xff0c;还是从x6…

【论文写作】如何写科技论文?万能模板!!!(以IEEE会议论文为例)

0. 写在前面 常言道&#xff0c;科技论文犹如“八股文”&#xff0c;有固定的写作模式。本篇博客主要是针对工程方面的论文的结构以及写作链条的一些整理&#xff0c;并不是为了提高或者润色一篇论文的表达。基本上所有的论文&#xff0c;都需要先构思好一些点子&#xff0c;有…

一文搞懂Session和JWT登录认证

前言 目前在开发的小组结课项目中用到了JWT认证&#xff0c;简单分享一下&#xff0c;并看看与Session认证的异同。 登录认证&#xff08;Authentication&#xff09;的概念非常简单&#xff0c;就是通过一定手段对用户的身份进行确认。 我们都知道 HTTP 是无状态的&#xf…

强化学习技巧

此软件包处于维护模式&#xff0c;请使用Stable-Baselines3 (SB3)获取最新版本。您可以在 SB3 文档中找到迁移指南。 本节的目的是帮助您进行强化学习实验。它涵盖了有关 RL 的一般建议&#xff08;从哪里开始、选择哪种算法、如何评估算法等&#xff09;&#xff0c;以及使用自…

【Linux】System V 共享内存、消息队列、信号量

&#x1f34e;作者&#xff1a;阿润菜菜 &#x1f4d6;专栏&#xff1a;Linux系统编程 system V共享内存介绍 System V 共享内存是一种进程间通信的机制&#xff0c;它允许多个进程共享一块物理内存区域&#xff08;称为“段”&#xff09;。System V 共享内存的优点是效率高&…

OTG是什么意思?

OTG是什么意思&#xff1f; OTG是怎么样实现的&#xff1f; TYPE-C接口的手机如何实现同时充电OTG功能&#xff1f; OTG是什么意思&#xff1f; OTG是On-The-Go的缩写&#xff0c;是一项新兴技术&#xff0c;主要应用于不同的设备或移动设备间的联接&#xff0c;进行数据交…

基于遥感的自然生态环境检测——实验三:生态因子提取

实验三&#xff1a;生态因子提取 一、实验目标 生态因子生成&#xff1b;生态因子归一化&#xff1b;生态环境评价 二、实验内容 根据经过大气校正后的影像生产土地覆盖指数、土壤指数以及坡度等&#xff0c;对土地覆盖指数、土壤指数以及坡度进行密度分割归一化&#xff1…

“SCSA-T学习导图+”系列:下一代防火墙

本期引言&#xff1a; 近年来&#xff0c;随着数字化业务带给我们高效和便捷的同时&#xff0c;信息暴露面的增加、网络边界的模糊化以及黑客攻击的产业化&#xff0c;使得网络安全事件相较以往成指数级增加。传统防火墙基于五元组的方式对进出网络的数据流量进行访问控制&…

JavaScript(JS)-1.JS基础知识

1.JavaScript概念 (1)JavaScript是一门跨平台&#xff0c;面向对象的脚本语言&#xff0c;来控制网页行为的&#xff0c;它能使网页可交互 (2)W3C标准&#xff1a;网页主要由三部分组成 ①结构&#xff1a;HTML负责网页的基本结构&#xff08;页面元素和内容&#xff09;。 …

【Linux网络服务】Linux网络设置

一、查看网络配置 1.1ifconfig 1.2ip a 1.3什么是mtu 最大传输单元MTU&#xff0c;是指网络能够传输的最大数据包大小&#xff0c;以字节为单位。MTU的大小决定了发送端一次能够发送报文的最大字节数。如果MTU超过了接收端所能够承受的最大值&#xff0c;或者是超过了发送路径…

EIGRP 配置,详解拓扑表,路由汇聚

1.3 EIGRP 拓扑&#xff0c;路由以及汇聚 1.3.1 实验目的 通过对 EIGRP 拓扑&#xff0c;路由以及汇聚相关实验的练习&#xff0c;掌握 EIGRP 建立拓扑信息的方式&#xff0c; 度量计算方法&#xff0c;如何调整度量&#xff0c;非等价负载均衡&#xff0c;以及 EIGRP 末节路…

做完自动化测试,但别让不会汇报毁了你...

pytest 是一个成熟的全功能Python测试工具&#xff0c;可以帮助您编写更好的程序。它与 python 自带的 unittest 测试框架类似&#xff0c;但 pytest 使用起来更简洁和高效&#xff0c;并且兼容 unittest 框架。pytest 能够支持简单的单元测试和复杂的功能测试&#xff0c;pyte…