手写-js数组去重(7种方法)

数组的去重方法有很多种,本文主要讲比较容易理解的几种

1.利用es6的set

set去重1(array.from)

/***
 * 数组去重
 * @params {array} arr 需要去重的数组
 * @returns {array} 去重后的数组
 */
function unique(arr) {
  // 先判断是否是数组,如果不是数组就直接返回一个空数组, 可根据实际需求变化。
  if (!Array.isArray(arr)) {
    console.log('type error!')
    return [];
  }
  // 通过array.from遍历set去重
  return Array.from(new Set(arr))
}
// 测试 start ------
let testArr = [1,3,3,3,3,3,4,5,6,6,6,7,8,9];
console.log(unique(testArr));
// 测试 end ------

set去重2: (使用解构和set)

/***
 * 去重: 使用es6的解构和set来达到去重的效果
 * @params {array} arr 需要去重的数组
 * @returns {array} 去重后的数组
 */
function unique(arr) {
  if (!Array.isArray(arr)) {
    console.log('type error!')
    return [];
  }
  return [...new Set(arr)]
}
// 测试 start ------
let testArr = [1, 3, 3, 3, 3, 3, 4, 5, 6, 6, 6, 7, 8, 9];
console.log(unique(testArr));
// 测试 end ------

2. 利用双层循环和splice

注意: splice会改变原数组

前提需要了解 == 和 object的关系

‘==’在进行比较的时候会进行类型的转换(不同类型进行比较的时候),例如 "" == false 会返回true, 可以使用‘===’解决。 同时 ‘==’无法比较NaN, NaN == NaN会返回false, 使用Object.is()解决。

Object.is() 确定两个值是否为相同值。如果以下其中一项成立,则两个值相同:

  • 都是 undefined
  • 都是 null
  • 都是 true 或者都是 false
  • 都是长度相同、字符相同、顺序相同的字符串
  • 都是相同的对象(意味着两个值都引用了内存中的同一对象)
  • 都是 BigInt 且具有相同的数值
  • 都是 symbol 且引用相同的 symbol 值
  • 都是数字且
    • 都是 +0
    • 都是 -0
    • 都是 NaN
    • 都有相同的值,非零且都不是 NaN

Object.is() 与 == 运算符并不等价。== 运算符在测试相等性之前,会对两个操作数进行类型转换(如果它们不是相同的类型),这可能会导致一些非预期的行为,例如 "" == false 的结果是 true,但是 Object.is() 不会对其操作数进行类型转换。

Object.is() 也不等价于 === 运算符。Object.is() 和 === 之间的唯一区别在于它们处理带符号的 0 和 NaN 值的时候。=== 运算符(和 == 运算符)将数值 -0 和 +0 视为相等,但是会将 NaN 视为彼此不相等。

/***
 * 去重: 使用双层遍历来进行比较的方式, 同时使用Object.is 来判断是否是相同数据,来避免NaN -0,+0的情况
 * @params {array} arr 需要去重的数组
 * @returns {array} 去重后的数组
 */
function unique(arr) {
  let arrLength = arr.length;
  for(let i = 0; i < arrLength; i++) {
    for(let j = i + 1; j < arrLength; j++) { // 当前位置和前一位数进行比较
      if (Object.is(arr[i], arr[j])) {
        arr.splice(j, 1);
        arrLength--;
        j--;
      }
    }
  }
  return arr;
}
// 测试 start ------
let testArr = [1, 3, 3, 3, 3, 3, 4, 5, 6, 6, 6, 7, 8, 9, NaN, NaN, null, NaN, +0, -0, +0, -0];
console.log(unique(testArr));
// 测试 end ------

3. 利用数组的findIndex + Object.is()

原理: 使用findIndex + Object.is来判断遍历的数组item是否已经存在于新数组中。

/***
 * 使用findIndex + Object.is来判断遍历的数组item是否已经存在于新数组中。
 * @params {array} arr 需要去重的数组
 * @returns {array} 去重后的数组
 */
function unique(arr) {
  let newArr = []; // 保存结果数组;
  arr.forEach(item => {
    if (newArr.findIndex(x => Object.is(x, item)) === -1) {
      newArr.push(item);
    }
  });
  return newArr;
}
// 测试 start ------
let testArr = [1, 3, 3, 3, 3, 3, 4, 5, 6, 6, 6, 7, 8, 9, NaN, NaN, null, NaN, +0, -0, +0, -0];
console.log(unique(testArr));
// 测试 end ------

4. 利用some和object.is()

同理可用 newArr.every(x => !Object.is(x, item), 但是没有some的性能好。

/***
 * 使用some + Object.is来判断遍历的数组item是否已经存在于新数组中。
 * @params {array} arr 需要去重的数组
 * @returns {array} 去重后的数组
 */
function unique(arr) {
  let newArr = []; // 保存结果数组;
  arr.forEach(item => {
    if (!newArr.some(x => Object.is(x, item))) {
      newArr.push(item);
    }
  });
  return newArr;
}
// 测试 start ------
let testArr = [1, 3, 3, 3, 3, 3, 4, 5, 6, 6, 6, 7, 8, 9, NaN, NaN, null, NaN, +0, -0, +0, -0];
console.log(unique(testArr));
// 测试 end ------

 5. 使用filter + Object.is()

使用filter + Object.is 来判断遍历的数组item是否已经存在于新数组中。

/***
 * 使用filter + Object.is来判断遍历的数组item是否已经存在于新数组中。
 * @params {array} arr 需要去重的数组
 * @returns {array} 去重后的数组
 */
function unique(arr) {
  let newArr = []; // 保存结果数组;
  arr.forEach(item => {
    if (!newArr.filter(x => Object.is(x, item)).length) {
      newArr.push(item);
    }
  });
  return newArr;
}
// 测试 start ------
let testArr = [1, 3, 3, 3, 3, 3, 4, 5, 6, 6, 6, 7, 8, 9, NaN, NaN, null, NaN, +0, -0, +0, -0];
console.log(unique(testArr));
// 测试 end ------

6. 使用map key的唯一特性

缺点: +-0的情况不太友好, 其他还都ok。

/***
 * 使用map来去重
 * @params {array} arr 需要去重的数组
 * @returns {array} 去重后的数组
 */
function unique(arr) {
  let newArr = []; // 保存结果数组;
  let mapTemp = new Map();
  arr.forEach(item => {
    mapTemp.set(item, item)
  });
  mapTemp.forEach((value, key) => { // forEach是map的函数,可以遍历map, 第一个值是value,第二个值是key
    newArr.push(value);
  })
  return newArr;
}
// 测试 start ------
let testArr = [1, 3, 3, 3, 3, 3, 4, 5, 6, 6, 6, 7, 8, 9, NaN, NaN, null, NaN, +0, -0, +0, -0];
console.log(unique(testArr));
// 测试 end ------

7. 使用对象的属性名不能重复的特性去重

缺点: 无法区分+-0

/***
 * 使用对象的属性名不能重复的特性去重
 * @params {array} arr 需要去重的数组
 * @returns {array} 去重后的数组
 */
function unique(arr) {
  let newArr = []; // 保存结果数组;
  let newObj = {};
  arr.forEach(item => {
    if(!newObj[item]) {
      newObj[item] = true;
      newArr.push(item);
    }
  });
  return newArr;
}
// 测试 start ------
let testArr = [1, 3, 3, 3, 3, 3, 4, 5, 6, 6, 6, 7, 8, 9, NaN, NaN, null, NaN, +0, -0, +0, -0];
console.log(unique(testArr));
// 测试 end ------

 

 

你可能感兴趣的:(前端八股文,javascript)