js数组去重是前端面试中经常被问的题目,考察了面试者对js的掌握,解决问题的思路,以及是否具有专研精神。曾经一位前端界大神告诉我,解决问题的方式有很多种,解决问题时多问问自己还有没有其他的方法,探求最优解决方案才能学到更多


方案一

 /**
   * 1.构建一个新数组
   * 2.遍历目标数组,依次取出每一个元素
   * 3.将取出的元素与新数组里面的所有元素进行比较,
   *    如果没有出现 -> 该元素添加到新数组中,
   *    如果出现  -> 处理下一个目标数组元素
   * */
  function distinct(arr) {
    console.time();    //跟踪方法的占用时长
    var result = [];    // 构建结果数组result
    for (var i = 0, len = arr.length; i < len; i++) {
      for (var j = 0, rlen = result.length; j <= rlen; j++) {
        if (arr[i] === result[j]) {
          break;
        }
        if (j == result.length) {
          result.push(arr[i]);
        }
      }
    }
    console.timeEnd();
    return result;
  }
方案优点:
  • 结果数组与目标数组的顺序保持一致
  • 思路简单,兼容性好
方案缺点:
  • 速度慢

方案二

/**
   *1.目标数组排序
   *2.遍历目标数组,检测数组中的第i 个元素与结果数组中最后一个元素是否相同,如果不同,则将该元素添加到结果数组中
   * */
  function distinct(arr) {
    console.time();
    var result = [];
    arr = arr.sort();
    for (var i = 0, len = arr.length; i < len; i++) {
      if (arr[i] !== result[result.length - 1]) {
        result.push(arr[i])
      }
    }
    console.timeEnd();
    return result;
  }
方案优点:
  • 方案中先排序,后遍历,速度比方法一快
方案缺点:
  • 方案中使用了数组排序sort,打乱了原有顺序

Tips:数组排序

js中提供了数组排序方法sort,使用时需要注意以下几点:

  1. 调用sort方法时改变了目标数组本身,非生成新数组
  2. sort方法默认按照字符顺序进行排序,不过提供了回调方法,可以自定义排序规则

现有一数组arr:1,11,23,56,3,4,5,7,562,67

按字符排序
arr.sort() // 1, 11, 23, 3, 4, 5, 56, 562, 67, 7
按数字大小:正序
arr.sort((a,b) => a-b) // 1, 3, 4, 5, 7, 11, 23, 56, 67, 562
按数字大小:倒序
arr.sort((a,b) => b-a) // 562, 67, 56, 23, 11, 7, 5, 4, 3, 1

方案三

/**
   * 利用ES6的 数据结构SET的无重复值特性
   * Array.from 将类数组转换成数组
   * */
  function distinct3(arr) {
    console.time();
    var result = Array.from(new Set(arr));
    console.timeEnd();
    return result;
  }
方案优点:
  • 代码简洁,执行速度快
方案缺点:
  • ES6语法,使用时需要考虑兼容性问题

方案四

 /**
   * 利用对象属性无重复的特点
   * 遍历目标数组,将值设置为对象属性
   * Object.keys 将对象的所有属性提取成一个数组
   * */
  function distinct(arr) {
    console.time();
    var result = {};
    for (var i = 0, len = arr.length; i < len; i++) {
      result[arr[i]] = '';
    }
    result = Object.keys(result);
    console.timeEnd();
    return result;
  }
方案优点:
  • 速度快
方案缺点:
  • 1 与 '1' 无法区分
  • 结果数组中的值全部为字符串
  • 占内存,相当于利用空间换时间

方案五

/**
   * Array.filter 数组过滤函数,只保留符合条件的值
   * indexOf 查找元素第一次出现的位置,所有第1次之后查找的元素位置都不符合条件
   * */
  function distinct(arr) {
    console.time();
    var result = arr.filter(function (elem, index, self) {
      return self.indexOf(elem) === index;
    });
    console.timeEnd();
    return result;
  }

测试

随机生成包含10000个数字的数组

function random() {
    var a = [];
    for (var i = 0; i < 10000; i++) {
      a.push(Math.ceil(i * Math.random()))
    }
    return a;
  }

现在执行上述去重方法,取5次测试结果的平均值:

  方法一 方法二 方法三 方法四 方法五
第一次 91.281 7.921 4.36 2.038 68.856
第二次 104.492 7.519 2.267 1.328 70.555
第三次 105.937 8.874 1.804 1.680 73.020
第四次 100.524 5.287 2.602 1.573 85.129
第五次 106.612 8.990 1.615 1.963 79.115
平均 101.769 7.718 2.529 1.716 75.335

从执行速度来看,方法四 < 方法三 < 方法二 < 方法五 < 方法一
方法四最快,方法一最慢。但是五种方法各有优缺点,使用时要根据实际情况选择适合的方案。