• 你真的会数组去重吗?去重方法汇总解析,看着一篇就够了


    去重方法

    在平时敲代码时,经常会遇到需要对数组进行去重的情况,若两个数组较小,此时使用任何一种去重方式都不会对效率产生太大影响,但当数组较大时,好的去重方法会明显提高运行效率。
    此外,去重方法也经常出现在各类面试笔试题中,为此我总结了一下各种去重方法,供大家参考。

    双重for循环

    这种方法是最直观最容易想到的了,代码如下:

       let arr = [
          {id: 1, name: 'lsm'},
          {id: 2, name: 'mjl'},
          {id: 1, name: 'lsm'}
        ]
        for (let i = 0; i < arr.length; i++) {
          for (let j = i + 1; j < arr.length; j++) {
            if (arr[i].id === arr[j].id) {
              arr.splice(j, 1)
              j--
            }
          }
        }
        console.log('arr--', arr)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    实现起来简单直观,但代码量大且效率低下,不够优雅。

    forEach+findindex实现去重

    利用findIndex 查找元素,根据返回结果组建最终结果数组,这样就优雅多了。

       let arr1 = [
          {id: 1, name: 'lsm'},
          {id: 2, name: 'mjl'},
          {id: 1, name: 'lsm'}
        ]
        let newArr1 = []
        arr1.forEach((item, index) => {
         arr1.findIndex(el => el.id == item.id) == index && newArr1.push(item)
        })
    
        console.log('newArr1', newArr1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    findIndex作用:找到遍历的数组中的第一个符合判断条件的值,并返回该值对应的索引。
    代码解析:

    1. 首先定义输出数组newArr1;
    2. 使用forEach遍历arr1,拿到其中的每个对象并使用findIndex查找此元素在arr1中第一次出现的index值。
    3. 当外层循环index值等于findIndex返回的index值时,表明此值第一次出现,则push到newArr1中。
    4. 如果外层循环index值bu等于findIndex返回的index值时,则表明此值不是第一次出现,则不push到newArr1中。

    filter+findIndex实现去重

    forEach+findindex方法的变种,代码如下:

    let arr2 = [
      {id: 1, name: 'lsm'},
      {id: 2, name: 'mjl'},
      {id: 1, name: 'lsm'}
    ]
    arr2 = arr2.filter((item, index) => {
      return arr2.findIndex(el => el.id == item.id) == index
    })
    console.log('arr3--', arr2)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这种方式,和forEach+findindex方式原理相同,我就不解释了。

    forEach搭配some实现去重

    针对的是由基本数据类型组成的数组,我们只要遍历一层,搭配indexOf、includes等方法,就可以实现去重,代码如下:

       let arr = [ 1, 1, 1, "1", "lsm", "52", 2, 81, 2, 81]
        let newArr = []
        arr.map((item, index) => {
          //!newArr.includes(item) && newArr.push(item)
          newArr.indexOf(arr1[i]) === -1 && newArr.push(arr1[i])
        })
        console.log('newArr--', newArr)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    如果数组内是引用类型的参数,在indexOf、includes无法使用时,可以使用some作为替代,上代码:

     let arr3 = [
          {id: 1, name: 'lsm'},
          {id: 2, name: 'mjl'},
          {id: 1, name: 'lsm'}
        ]
        let newArr3 = []
        arr3.forEach((item, index) => {
          !newArr3.some(el => el.id == item.id)  && newArr3push(item)
        })
        console.log('newArr2', newArr2)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    some作用:判断数组中是否存在满足条件的值,如果有则返回true,完整遍历不会终止循环,可以使用return自行终止(此例中并没用到该特性)

    filter和find

    此方法仍然为filter+findIndex的变种,使用find替代findIndex,代码如下:

    let arr4 = [
          {id: 1, name: 'lsm'},
          {id: 2, name: 'mjl'},
          {id: 1, name: 'lsm'}
        ]
        arr4 = arr4.filter(item => {
          return arr4.find(el => el.id == item.id) == item
        })
        console.log('arr4', arr4)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    find返回的是符合条件的遍历项,需要注意的是,这里不推荐使用find,因为find方法比较的是引用地址,如果数组中的对象地址出现相同的情况则达不到去重效果,如:

    let obj = {id: 10, name: 'lsm'}
    let arr = []
    arr.push(obj)
    arr.push(obj)
    //arr中的两个对象引用地址实际上是一样
    //Set不能对对象去重,但是这种情况可以
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    find作用:找出符合判断条件的第一项,并进行返回

    map结合some | find | findexIndex

    最终总结:

    1. 引用类型的数组要进行去重操作,主要实现的方式为双重循环。
    2. 外层循环可以是forEach、map等方法,为内层循环提供去重对象。
    3. 内层循环借用各类函数实现去重,内层使用的函数需要有返回值用于判断是否重复,可以是some,findIndex,find等。
      最后将map和some、find、findexIndex方法汇总一下:
    let arr5 = [
      {id: 1, name: 'lsm'},
      {id: 2, name: 'mjl'},
      {id: 1, name: 'lsm'}
    ]
    let newArr5 = []
    arr5.map((item, index) => {
      // !newArr5.some(el => el.id == item.id) && newArr5.push(item)
      // arr5.findIndex(el => el.id === item.id) === index && newArr5.push(item)
      arr5.find(el => el.id === item.id) === item && newArr5.push(item)
    })
    console.log('arr5', newArr5)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    作者简介 :游逸,高级软件工程师,7年开发经验,喜欢分享干货与关注技术前沿,欢迎一起交流学习

  • 相关阅读:
    跨平台编程开发工具Xojo 2023 Release mac中文版功能介绍
    MAC手动修复『已损坏』问题 终端运行命令报错处理
    矩阵分析与计算学习记录-广义逆矩阵
    Lua如何调用C程序库
    缓存与数据库双写一致性问题解决方案
    【论文不精读】Reinforced Path Reasoning for Counterfactual Explainable Recommendation
    苹果急了,Type-C将一统天下,欧盟法案有望今年实现
    项目运维工作的心得总结
    [附源码]计算机毕业设计校园疫情管理系统Springboot程序
    基于typescript+express实现一个简单的接口权限验证
  • 原文地址:https://blog.csdn.net/talenter111/article/details/126261590