【面试题】数组去重的五种方法

简介: 【面试题】数组去重的五种方法

别着急,这篇文章只节选了简单的,好玩的,古老的,有实际讲解意义的去重方法,除了去重的实现以外,我还将和您分享这其中的其他细节和拓展

您或许不理解,为什么只有五种?

当然,我可以举例出更多的例子来,但那有什么意义呢?工作中用不到那么多,会其中一二就可以。即使是面试,能说出五种也是完全足够的。所以,我们完全没有必要去记忆更多的去重方式。

大厂面试题分享 面试题库

前端面试题库 (面试必备) 推荐:★★★★★

地址:前端面试题库

五种方式

最简单的方法,ES6的Set去重(最推荐)

这个方法是我日常开发中最喜欢用的方法,因为,他的使用方法是所有去重中最简单的。而我是一个懒癌患者。

new Set是ES6新推出的一种类型。他和数组的区别在于,Set类型中的数据不可以有重复的值。当然,数组的一些方法Set也无法调用。

使用方法:其实很简单,将一个数组转化为Set数据,再转化回来,就完成了去重。

const arr = [1,1,2,2,3,3,4,4,5,5];
    const setData = Array.from(newSet(arr));
    console.log(setData);
复制代码

图例↓

但是Set去重有一个弊端,他无法去重引用类型的数据。比如对象数组。

图例:

所以如果您的数组中都是值类型的数据(比如全string或者全number),那么使用Set进行去重一定是首选,会为您减少很多的麻烦。

最古老的方法,双重for循环去重

在很早以前,还没有Set,没有map,filter的时候,双重for循环几乎是去重的唯一方式。

//双重循环去重consthandleRemoveRepeat = (arr) => {
    for (let i=0,len = arr.length; i < len; i++) {
        for (let j = i + 1; j < len; j++) {
            if (arr[i] === arr[j]) {
                arr.splice(j, 1);
                j--;
                len--;
            }
        }
    }
    return arr;
};
复制代码

图例:

这里有一个有意思的地方,或许您不太明白,为什么我的for循环的初始表达式中声明了两个东西:let i = 0;len = arr.length;

我来给您解答:

被圈起来的三个表示的是for循环的三个表达式,依次分别是:初始表达式判断表达式自增表达式。其中,初始表达式在for循环开始的时候会执行一次,以后就不会再执行了,但是判断表达式自增表达式会在每一次循环的时候都去执行。

如果您不太理解文字表达,没关系,我画了张图。

您或许已经发现,后一个圈中的内容会陷入一个循环。

但这和我们一开始len = arr.length有什么关系呢?

值得注意的是,如果一开始定义,那么每一次循环,都需要走 arr.length,length可是个方法,虽然他的消耗并不大,但在for循环中这个消耗会被方法,假设这个循环需要循环10000次呢,length就会被执行10000次。

最鸡肋的去重方式,indexOf去重

indexOf还是相对简单又鸡肋。为什么说他鸡肋呢?说难吧,indexOf方法确实比上文的双重for循环简单。说简单吧,嘿,他没Set方法去重来的更简单。所以鸡肋。

//去重consthandleRemoveRepeat = (arr) => {
    let repeatArr = [];
    for (let i = 0,len = arr.length ; i < len; i++) 
     if (repeatArr.indexOf(arr[i]) === -1)  repeatArr.push(arr[i])
    return repeatArr;
}
复制代码

图例:

同样的,这个方法也有一个细节点,您或许已经发现了,上文的if和for没有花括号;是的;for和if都默认对下面一条语句负责。在没有必要的情况下,不用多加一个{}。

或许您会觉得这不可读,这就是有意思的地方了,这是一个工具类方法,注定被藏在utils中的一个方法,他无关业务逻辑,并不需要有太大可读性。

而且,这么写还有一个很原因:给人的视觉冲击会比较大。说点人话就是 -----很装逼;

一种类似于indexOf的去重方法,includes去重

使用includes的去重方法和indexOf不能说很像,基本上一模一样。变换的仅仅只是判断方法。

includes的判断方法更简单了。循环数组的每一样,用新数组检测当前数组中是否包含数组项,如果不包含,则追加该元素

consthandleRemoveRepeat = (arr) => {
    let repeatArr = [];
    for (let i = 0,len = arr.length ; i < len; i++)
        if (!repeatArr.includes(arr[i])) repeatArr.push(arr[i])
    return repeatArr;
}
复制代码

图例

includes方法在除了去重以外的场景,还是很好用的。

最有趣的去重方法,使用filter去重。

使用filter配合indexOf进行的去重过程,真的可以非常的简单且富含趣味性。

//去重consthandleRemoveRepeat = (arr) => arr.filter((item,index) => arr.indexOf(item,0) === index);
复制代码

是的,没了,就一行。

图例

您是否没有反应过来?乍一看,不知道他是怎么完成去重的。

小问题,我为您解答疑惑。

indexOf的特性是返回被查找的目标中包含的第一个位置的索引

如图,下标为0和下标为4的位置存储的都是“1”。但是indexOf()只返回了0。因为indexOf的特性是返回被查找的目标中包含的第一个位置的索引。

同样的,我们可以利用这个特性。来完成去重,文字描述恐怕很难表达准确,您可以看看下面的这张图。

您或许会问:如果要去重对象数组怎么办?

去除对象数组的方式他并不是很稳定,这不像我们去重值类型数据的数组,上面的五种方法随便复制一种,往里面一调用就好了。绝对不会出问题。

但是对象数组去重,需要有一个去重条件,也就是根据哪个字段进行去重。

用双重循环去重举个例子:

图例

如上图,我们就是拿数据的id作为去重条件的。

像这样的对象数组就不能直接提供方法,因为每一个场景下的对象数组都不一定一样。我这是根据id去重,万一其他地方需要根据其他字段去重呢。

所以,如果您需要去重对象,根据上方的截图中的代码。使用双重for循环的方法,自己自定义一个可以满足您当前业务需求的去重方法。

大厂面试题分享 面试题库

前端面试题库 (面试必备) 推荐:★★★★★

地址:前端面试题库

相关文章
|
15天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
55 4
|
2月前
|
ARouter 测试技术 API
Android经典面试题之组件化原理、优缺点、实现方法?
本文介绍了组件化在Android开发中的应用,详细阐述了其原理、优缺点及实现方式,包括模块化、接口编程、依赖注入、路由机制等内容,并提供了具体代码示例。
47 2
|
3月前
|
Java
【Java基础面试二十】、介绍一下Object类中的方法
这篇文章介绍了Java中Object类的常用方法,包括`getClass()`、`equals()`、`hashCode()`、`toString()`、`wait()`、`notify()`、`notifyAll()`和`clone()`,并提到了不推荐使用的`finalize()`方法。
【Java基础面试二十】、介绍一下Object类中的方法
|
3月前
|
Java API 索引
【Java基础面试二十四】、String类有哪些方法?
这篇文章列举了Java中String类的常用方法,如`charAt()`、`substring()`、`split()`、`trim()`、`indexOf()`、`lastIndexOf()`、`startsWith()`、`endsWith()`、`toUpperCase()`、`toLowerCase()`、`replaceFirst()`和`replaceAll()`,并建议面试时展示对这些方法的熟悉度,同时深入理解部分方法的源码实现。
【Java基础面试二十四】、String类有哪些方法?
|
3月前
|
Java
【Java集合类面试三十】、BlockingQueue中有哪些方法,为什么这样设计?
BlockingQueue设计了四组不同行为方式的方法用于插入、移除和检查元素,以适应不同的业务场景,包括抛异常、返回特定值、阻塞等待和超时等待,以实现高效的线程间通信。
|
3月前
|
SQL 安全 测试技术
[go 面试] 接口测试的方法与技巧
[go 面试] 接口测试的方法与技巧
|
3月前
|
机器学习/深度学习 算法 Python
【机器学习】面试问答:决策树如何进行剪枝?剪枝的方法有哪些?
文章讨论了决策树的剪枝技术,包括预剪枝和后剪枝的概念、方法以及各自的优缺点。
59 2
|
3月前
|
机器学习/深度学习
【机器学习】面试题:LSTM长短期记忆网络的理解?LSTM是怎么解决梯度消失的问题的?还有哪些其它的解决梯度消失或梯度爆炸的方法?
长短时记忆网络(LSTM)的基本概念、解决梯度消失问题的机制,以及介绍了包括梯度裁剪、改变激活函数、残差结构和Batch Normalization在内的其他方法来解决梯度消失或梯度爆炸问题。
151 2
【多线程面试题 二】、 说说Thread类的常用方法
Thread类的常用方法包括构造方法(如Thread()、Thread(Runnable target)等)、静态方法(如currentThread()、sleep(long millis)、yield()等)和实例方法(如getId()、getName()、interrupt()、join()等),用于线程的创建、控制和管理。
|
3月前
|
运维 监控 算法
[go 面试] 优化线上故障排查与性能问题的方法
[go 面试] 优化线上故障排查与性能问题的方法
下一篇
无影云桌面