• js 数组去重十几种解法,基础知识扎实吗?(附数组方法)


    前言

    看到有位掘友的座右铭,Talk is cheap, show me the code. 这句话很有意思。

    一 、基本类型的数组去重

    1、最直接高效的方法【扩展运算符 + Set()】

    在实际工作中推荐直接使用这种方法去重,方便实惠。Set对象是值的集合,你可以按照插入的顺序迭代它的元素。 Set中的元素只会出现一次,即 Set 中的元素是唯一的。

    function removeDuplicate_1(arr) {
      return [... new Set(arr)]
    }
    复制代码

    上面其实相当于
    let set = new Set(arr); return [... set];
    这里set 是一个集合对象,通过...结构的方式,将每一项解构到数组中。

    2、使用数组api reduce 方法【需要先排序】

    下面的if条件可以这样写,if(prev.indexOf(cur) === -1) ,是indexOf()方法,prev里还没有,就push 近result.push, 有就不入result数组,

    function removeDuplicate_2(arr) {
      arr.sort((a, b) => a - b) // 数组升序排序
      return  arr.reduce((prev, cur) => { // 这里return最后结果就是prev 的最后结果
      // 第一次数组为空时|| prev 数组的最后一项不等于arr 的下一项的话 ,把当前项cur push到prev数组中,
        if (prev.length === 0 || (prev[prev.length - 1] !== cur)) { 
          prev.push(cur)
        }
        return prev;  // 这里返回的prev 会成为 reduce(prev,cur)这里prev 的新值
      }, [])
    }
    复制代码

    reduce 方法介绍

    一般写arr.reduce((p,c)=>{ fn content;return p },init),将下面的具体参数介绍对号入座。

    概括:reduce参数包括一个函数和一个初始值,初始值可选,函数有四个参数可选,有初始值 时previousValue = 初始值(initialValue), currentValue = 数组第一项arr[0],无初始值时, p = arr [0], c = arr[1]。 return的结果作为下一次迭代的 p的初始值。

    • 一个 “reducer” 函数,包含四个参数:

      • previousValue:上一次调用 callbackFn 时的返回值。在第一次调用时,若指定了初始值 initialValue,其值则为 initialValue,否则为数组索引为 0 的元素 array[0]
      • currentValue:数组中正在处理的元素。在第一次调用时,若指定了初始值 initialValue,其值则为数组索引为 0 的元素 array[0],否则为 array[1]
      • currentIndex:数组中正在处理的元素的索引。若指定了初始值 initialValue,则起始索引号为 0,否则从索引 1 起始。
      • array:用于遍历的数组。
    • initialValue 可选

    • 作为第一次调用 callback 函数时参数 previousValue 的值。若指定了初始值 initialValue,则 currentValue 则将使用数组第一个元素;否则 previousValue 将使用数组第一个元素,而 currentValue 将使用数组第二个元素。 用途

    1、求数组所有值的和

    let sum = [0, 1, 2, 3].reduce(function (previousValue, currentValue) {
      return previousValue + currentValue
    }, 0)
    // sum is 6
    
    复制代码

    2 、累加对象数组里的值

    let initialValue = 0
    let sum = [{x: 1}, {x: 2}, {x: 3}].reduce(
        (previousValue, currentValue) => previousValue + currentValue.x
        , initialValue
    )
    
    console.log(sum) // logs 6
    
    复制代码

    更多实例参考官方文档

    看看有无初始值的情况
    无初始值时 reduce() 如何运行

    假如运行以下无初始值的 reduce() 代码:

    const array = [15, 16, 17, 18, 19];
    
    function reducer(previous, current, index, array) {
      const returns = previous + current;
      console.log(`previous: ${previous}, current: ${current}, index: ${index}, returns: ${returns}`);
      return returns;
    }
    
    array.reduce(reducer);
    复制代码

    callback 被调用四次,每次调用的参数和返回值如下表:

    callback iterationpreviousValuecurrentValuecurrentIndexarrayreturn value
    first call15161[15, 16, 17, 18, 19]31
    second call31172[15, 16, 17, 18, 19]48
    third call48183[15, 16, 17, 18, 19]66
    fourth call66194[15, 16, 17, 18, 19]85

    由 reduce() 返回的值将是最后一次回调返回值(85)。

    有初始值时 reduce() 如何运行

    在这里,我们以相同的算法 reduce 同一个数组,但提供 10 作为初始值:

    [15, 16, 17, 18, 19].reduce( (previousValue, currentValue, currentIndex, array) => previousValue + currentValue, 10 )
    复制代码

    Copy to Clipboard

    callback iterationpreviousValuecurrentValuecurrentIndexarrayreturn value
    first call10150[15, 16, 17, 18, 19]25
    second call25161[15, 16, 17, 18, 19]41
    third call41172[15, 16, 17, 18, 19]58
    fourth call58183[15, 16, 17, 18, 19]76
    fifth call76194[15, 16, 17, 18, 19]95

    这种情况下 reduce() 返回的值是 95

    3、使用一个for循环解决【需要先排序】

    1、声明一个新数组result来存放,去重后的数组 。

    2、给数组排序。

    3、循环排序后的数组, 若第i项不等于第i-1项,则把此项内容push到result数组, 注意这里和常规的,用当前项于下一项对比的方式不同, arr[i- 1] 这里是arr[-1],结果是undefined的,js 语言的特性,所以可以这样操作吧,思考一下(1),用if(arr[i] !== arr[i + 1])可以吗,评论区说出你的答案,为什么?

    4、 返回结果result

    function removeDuplicate_3(arr) {
      let result = []
      arr.sort((a, b) => a - b)
      for (let i = 0; i < arr.length; i++) {
        if (arr[i] !== arr[i - 1]) {
          result.push(arr[i])
        }
      }
      return result
    }
    复制代码

    sort 方法介绍

     arr.sort((a, b) => a - b) // 升序
      arr.sort((a, b) => b - a) // 降序
    复制代码

    4、使用数组api indexOf() 方法

    function removeDuplicate_4(arr) {
      let result = [];
      for (let i = 0; i < arr.length; i++) {
        if (result.indexOf(arr[i]) == -1) {
          result.push(arr[i])
        }
      }
      return result;
    }
    复制代码

    indexOf() 方法介绍

    indexOf() 方法返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。
    概括:接收两个参数,返回下标值。arr.indexOf(要查找的元素,从那个位置开始查找)

    示例

    var array = [2, 5, 9];
    array.indexOf(2);     // 0
    array.indexOf(7);     // -1
    array.indexOf(9, 2);  // 2
    array.indexOf(2, -1); // -1
    array.indexOf(2, -3); // 0
    
    复制代码

    indexOf()方法详细介绍

    5、使用数组api Array.from() 方法和 Set 对象

    function removeDuplicate_5(arr) {
      return Array.from(new Set(arr))
    }
    复制代码

    Array.from()  方法对一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例。

    概括: 接收三个参数,返回数组。Array.from(要处理的类数组对象,fn【回调函数可选】, this【执行回调函数时的this指向,可选】)

    注意: 使用的时Array.from ,而不是数组实例arr.from,类似于Java的静态方法用类名调用。

    Array.From() 详细介绍

    6、使用一个for循环 、利用对象的存储特性

    function removeDuplicate_6(arr) {
      let result = [], obj = {};
      for (let item of arr) {
        if (!obj[item]) {
          result.push(item);
          obj[item] = 1
        } else {
          obj[item]++
        }
      }
      return result;
    }
    复制代码

    7、使用数组api filter 和indexOf 方法结合原型的this的call调用

    function removeDuplicate_7(arr) {
      return Array.prototype.filter.call(arr, (item, index) => {
        return arr.indexOf(item) === index
      })
    }
    
    复制代码

    8 、利用数组快慢指针的方式

    function removeDuplicate_8(arr) {
      let fast = 0, low = -1, result = [];
      arr.sort((a,b) => a - b)
      while (fast < arr.length) {
        if (arr[fast] !== arr[low]) {
          result.push(arr[fast])
        }
        fast++
        low++
      }
      return result;
    }
    复制代码

    二、数组对象类型的去重

    9 、利用数组的filter对象和 Map 对象去重数组里的对象

    Map 对象保存键值对,并且能够记住键的原始插入顺序。任何值(对象或者原始值) 都可以作为一个键或一个值。 Map 对象

    filter()  方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。

    
    let arr_obj = [
      {
        id: 1,
        name: '张三',
        age: 18,
        sex: 1
      },
      {
        id: 2,
        name: '李四',
        age: 20,
        sex: 2
      },
      {
        id: 1,
        name: '张三',
        age: 18,
        sex: 1
      },
      {
        id: 3,
        name: '王老五',
        age: 18,
        sex: 2
      },
      {
        id: 4,
        name: '王老五',
        age: 18,
        sex: 2
      }
    ]
    function removeDuplicate_10(arr, attr) {
      const result = new Map();
      return arr.filter((item) => !result.has(item[attr]) && result.set(item[attr], 1))
    }
    
    console.log(arr_obj);
    console.log(removeDuplicate_10(arr_obj, 'name')); // 以对象姓名去重
    复制代码

    上面filter()里面的内容会不好理解吗它相当于

    
    function removeDuplicate_11(arr, attr) {
      const result = new Map();
      let fn = (item) => {
        if(!result.has(item[attr])) {
         return result.set(item[attr], 1)
        }
      }
      return arr.filter(fn)
    }
    复制代码

    !result.has(item[attr]) && result.set(item[attr], 1)) 相当于

     if(!result.has(item[attr])) {
         result.set(item[attr], 1)
     }
     //由于箭头函数没有带{}花括号,所以是有return的, 所以会相当于这样
      if(!result.has(item[attr])) {
         return result.set(item[attr], 1)
        }
    复制代码

    去重前

    [
      { id: 1, name: '张三', age: 18, sex: 1 },
      { id: 2, name: '李四', age: 20, sex: 2 },
      { id: 1, name: '张三', age: 18, sex: 1 },
      { id: 3, name: '王老五', age: 18, sex: 2 },
      { id: 4, name: '王老五', age: 18, sex: 2 }
    ]
    复制代码

    去重后

    [
      { id: 1, name: '张三', age: 18, sex: 1 },
      { id: 2, name: '李四', age: 20, sex: 2 },
      { id: 3, name: '王老五', age: 18, sex: 2 }
    ]
    复制代码

    以id 去重

    console.log(removeDuplicate_8(arr_obj, 'id'));
    [
      { id: 1, name: '张三', age: 18, sex: 1 },
      { id: 2, name: '李四', age: 20, sex: 2 },
      { id: 3, name: '王老五', age: 18, sex: 2 },
      { id: 4, name: '王老五', age: 18, sex: 2 }
    ]
    
    复制代码

    10 、使用数组方法reduce和对象特性

    思路是创建一个空对象,判断对象里有没有该属性的值,没有就吧该项push 到数组存储

    function removeDuplicate_12(arr, attr) {
      let obj = {}
      return arr.reduce((prev,curr) =>{
        // 这种三元运算符的方式是不是不好理解,看看下面10的做法,转化为if判断就好理解了。
        obj[curr[attr]] ? '' : obj[curr[attr]] = true && prev.push(curr) // ''为空的意思
         // 写法上也可以 为undefined 
        // obj[curr[attr]] ? undefined : obj[curr[attr]] = true && prev.push(curr)
        return prev
      },[])
    }
    console.log(removeDuplicate_12(arr_obj, 'name'));
    复制代码

    11、使用for of 循环加对象特性。

    思路和9的类似,知识迭代方式不同。

    function removeDuplicate_13(arr, attr) {
      let obj = {}, result = [];
      for(let item of arr){
        if(!obj[item[attr]]) {
          result.push(item)
          obj[item[attr]] =  true
        }
      }
      return result;
    }
    console.log(removeDuplicate_13(arr_obj, 'id'));
    复制代码

    相关文章参考

    JS对象数组去重的三种方法

    数组去重

    来源:https://juejin.cn/post/7081572865220280333
  • 相关阅读:
    NOI2005维修数列
    BZOJ1208 [HNOI2004]宠物收养所
    BZOJ3223 文艺平衡树
    BZOJ [JSOI2008]星球大战starwar
    BZOJ1013 [JSOI2008]球形空间产生器sphere
    小程序之底部tabBar
    es6
    vue.js安装
    模块打包工具webpack
    highchart
  • 原文地址:https://www.cnblogs.com/konglxblog/p/16519389.html
Copyright © 2020-2023  润新知