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

news2025/5/24 15:53:32

文章目录

  • 📋前言
  • 🎯什么是数组去重,运用场景是什么?
  • 🎯常用的数组去重方法
    • 🧩使用 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]

📝最后

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

概率图降低表示需要的参数指的是什么?(贝叶斯网络) 结构化概率模型

深度学习中经常要对概率密度建模。对于多维度随机变量来说&#xff0c;这有些困难。概率化结构&#xff08;既图模型&#xff09;是处理这个问题的手段之一。这引出了两个问题。为什么建模困难&#xff1f;图模型怎样解决了这个困难&#xff1f; 关于这个问题&#xff0c;花书…

图片怎么压缩到200K以内,这3个图片压缩方法,简单有效

你没有遇到过上传图片到网站的时候&#xff0c;图片太大不能上传的情况&#xff1f;还有&#xff0c;许多报名照片要求小于200K&#xff0c;可是照片超过这个大小&#xff0c;应该如何压缩呢&#xff1f;下面我给大家带来3个图片压缩的方法&#xff0c;既能快速压缩图片大小&am…

深度学习技巧应用7-K折交叉验证的实践操作

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下深度学习技巧应用7-K折交叉验证的实践操作。K折交叉验证是一种机器学习中常用的模型验证和选择方式&#xff0c;它可以将数据集分为K个互斥的子集&#xff0c;其中K-1个子集作为训练集&#xff0c;剩下1个子集作为验…

Hive设置元数据支持中文显示

在hive中建外部表时遇见到这样一个问题&#xff0c;就是表字段的中文注释在desc 表结构时看不了&#xff0c;发现原来是Hive的元数据库没有设置支持中文显示 第一步&#xff0c;在元数据库metastore完成初始化后&#xff0c;再次登录MySQL [roothurys24 hurys_table_data]# m…

成功解决:OSError: [E050] Can’t find model ‘en_core_web_sm’.

成功解决OSError: [E050] Can’t find model ‘en_core_web_sm’. 问题描述 在安装spacy包之后&#xff0c;再加载’en_core_web_sm’语言模型时&#xff0c;报出OSError: [E050] Can’t find model ‘en_core_web_sm’. It doesn’t seem to be a Python package or a valid…

【Java】插入排序和希尔排序---图解超详细

目录 插入排序 插入排序的核心图解 希尔排序 希尔排序详细图解 插入排序 插入排序的交换精髓在于 每次随着i的扩大,i走过的路径都是有序的,这和冒泡的思想有异曲同工之处,冒泡是i走一次,数组的最后变成有序的,而插入排序是 插入排序是 i 在前面 j在后面 插入排序的核心图解…

C- 符号

文章目录 符号#ifdef-#endif\接续符转义旋转光标数字倒计时 单引号-双引号逻辑运算符&& ||短路 位运算符异或位运算最好使用定义好的宏左移右移 后置前置复杂表达式 取整0向取整(C中默认取整方式)floor地板取整ceilround 四舍五入 取模取余和取模一样吗? 运算符优先级…

两小时让你全方位的认识文件(一)

想必友友们在生活中经常会使用到各种各样的文件&#xff0c;那么我们是否了解它其中的奥秘呢&#xff0c;今天阿博就带领友友们深入地走入文件&#x1f6e9;️&#x1f6e9;️&#x1f6e9;️ 文章目录 一.为什么使用文件二.什么是文件三.文件的打开和关闭四.文件的顺序读写 一…

网页自动化工具DrissionPage

逛Github时偶然看到的开源项目&#xff0c;DrissionPage是一款新的基于 python 的网页自动化工具。 笔者已测试过&#xff0c;给大家推荐下。 项目地址&#xff1a;https://gitee.com/g1879/DrissionPage 安装测试 安装命令 pip install DrissionPage测试 from Drissio…

unity | 处理string常用的知识(持续更新)

一、转义字符和的用法 1.常规用法 我们现在有一行字&#xff0c;但是我对它的格式之类的有要求 例&#xff1a;天无绝人之路&#xff0c;条条道路通罗马。 我想打成&#xff1a; 天无绝人之路&#xff0c; 条条道路通罗马。 换行前&#xff0c;写法是&#xff1a; string s …

科海思—美国杜笙Tulsimer中国区总代理,制糖脱色树脂A-722

一、产品介绍 具有控制孔径的大孔强碱性Ⅰ型阴特种脱色用离子交换树脂 Tulsimer A-722是一款具有便于颜色和有机物去除的控制孔径的&#xff0c;专门开发的大孔强碱性Ⅰ型阴离子交换树脂。 Tulsimer A-722 &#xff08;氯型&#xff09;专门应用于糖浆脱色。 Tulsimer A…

Python学习简记

常用数据类型 整数类型int 二进制以0b开头八进制以0o开头十六进制以0x开头 这里还有一个值得注意的点&#xff1a;python中的整型是“无限长”的&#xff0c;因此它可以表示任何数 浮点数 python中只有float作为浮点数&#xff0c;没有double 主要注意python中对浮点数与Decima…

Spring系统架构与主要概念

Spring系统架构与主要概念 Spring Framework系统架构Core Container 核心容器AOP 层数据层Web层测试层 业务逻辑Spring之前遇到的问题解决方案 Spring核心概念IOC&#xff08;Inversion of Control&#xff09;控制反转DI&#xff08;Dependency Injection&#xff09;依赖注入…

SRv6实践项目(四):基于YANG的配置下发

在本章节&#xff0c;主要是了解YANG是什么&#xff0c;以及基于YANG下发配置的工作原理&#xff1a; 1.什么是YANG 在介绍之前&#xff0c;为了给大家一个最直观的感受&#xff0c;我们打开yang工具&#xff0c;它被打包成一个容器了&#xff0c;可以轻松的使用&#xff0c;…

完美解决丨1. **`SyntaxError: invalid syntax`**

SyntaxError: invalid syntax 因为没有符合语法要求&#xff0c;导致报错。 解决办法&#xff1a; 语法错误的原因主要是代码的风格&#xff0c;例如&#xff1a; 左括号或者右括号没有配对&#xff1b;左括号或者右括号没有放在语句的正确位置&#xff1b;缺少冒号&#xff1…

Window10下安装DPDK

由于我装的是vs2019&#xff0c;打开Visual Studio Installer&#xff0c;在可选下&#xff0c;选择Windows 10 SDK&#xff0c;点击修改。 右键此电脑属性&#xff0c;查看Windows10版本。 安装WDK&#xff0c;打开网址https://learn.microsoft.com/zh-cn/windows-hardware/…

计算机系统-链接

例行前言&#xff1a; 本篇不是学习课程时的笔记&#xff0c;是重看这本书时的简记。对于学习本课程的同学&#xff0c;未涉及的内容不代表考试不涉及&#xff0c;部分省略的部分是在该课程的讨论课中学习的(PIC&#xff0c;放出了我在讨论课中的PPT作为参考)&#xff0c;核心…

Sentinel使用

文章目录 一. 初识Sentinel1. 雪崩问题及解决方案2. 服务保护技术对比3. Sentinel介绍和安装4. 微服务整合Sentinel 二. 限流规则1. 快速入门2. 流控模式3. 流控效果4. 热点参数限流 三. 隔离与降级—调用方保护方案1. FeignClinet整合sentinel2. 线程隔离&#xff08;舱壁模式…

vue3中的单文件组件<script setup>和setup函数区别 详解

文章目录 简介基本语法变量和方法多的使用注册组件动态组件使用外部文件方法组件通信props与defineProps、emitdefineEmitsdefineExpose 获取 attrs、slots 和useAttrs、useSlots 方法与普通的 < script > 一起使用v-bind() CSS变量注入style的新特性之global对await异步…

行业认可,知道创宇入选安全牛第十版全景图30个细分领域

近日&#xff0c;国内网络安全领域专业媒体安全牛正式发布了第十版《中国网络安全行业全景图》&#xff08;以下简称“全景图”&#xff09;&#xff0c;知道创宇凭借过硬的技术实力及成熟的市场应用获得行业认可&#xff0c;入围10项一级安全分类共计30项二级细分领域&#xf…