数组去重的六种解法

假设原数组:

ini 复制代码
const arr = [1, 2, 2, 3, 4, 4, 4, 5, 1];

1. 双 for 循环(最基础、兼容性最好)

思路:外层遍历,内层对比,发现重复就删除。

ini 复制代码
function unique1(arr) {
  // 浅拷贝原数组,避免修改原数组
  const newArr = [...arr];
  for (let i = 0; i < newArr.length; i++) {
    for (let j = i + 1; j < newArr.length; j++) {
      // 如果发现重复,删除当前项
      if (newArr[i] === newArr[j]) {
        newArr.splice(j, 1);
        // 删除后下标回退,防止跳过元素
        j--;
      }
    }
  }
  return newArr;
}

console.log(unique1(arr)); // [1,2,3,4,5]

使用双重for循环解决数组去重问题,他的时间复杂度为(O(n^2)),空间复杂度为(O(1))


2. indexOf 方法

思路:判断元素第一次出现的位置是否等于当前下标,不是则重复。

ini 复制代码
function unique2(arr) {
  const newArr = [];
  for (let i = 0; i < arr.length; i++) {
    // 第一次出现才 push
    if (newArr.indexOf(arr[i]) === -1) {
      newArr.push(arr[i]);
    }
  }
  return newArr;
}

console.log(unique2(arr)); // [1,2,3,4,5]

indexOf() 是js里提供的查找数组元素下标的api,是数组 / 字符串 都能用的方法,作用是:查找某个元素第一次出现的位置,返回它的下标;找不到就返回 -1。 每次调用 indexOf 都会从头遍历数组,所以时间复杂度也为(O(n^2))。


3. filter 过滤器(简洁优雅)

思路 :利用 filter 保留第一次出现的元素。

javascript 复制代码
function unique3(arr) {
  return arr.filter((item, index) => {
    // 只保留第一次出现的元素
    return arr.indexOf(item) === index;
  });
}

console.log(unique3(arr)); // [1,2,3,4,5]

Array.prototype.filter(),js提供的一种过滤器方法。它会遍历数组里的每一项 ,你写一个条件,满足条件的留下,不满足的扔掉 ,最后返回一个新数组

javascript 复制代码
数组.filter(function(当前项, 下标, 原数组){
  return 满足条件就返回 true / false
})

最常用的就两个:

  • item:当前正在遍历的元素
  • index:当前元素的下标

因此filter+indexOf()的时间复杂度为(O(n^2))

filter 3 大核心特点

  1. 返回新数组,不影响原来的数组
  2. 必须写 return,不写会全过滤掉
  3. 遍历数组里每一项,自动循环

4. sort 排序 + 相邻对比

思路:先排序,重复元素会挨在一起,再遍历去重。

ini 复制代码
function unique4(arr) {
  if (!arr.length) return [];
  // 先排序
  const sortedArr = [...arr].sort();
  const newArr = [sortedArr[0]];

  for (let i = 1; i < sortedArr.length; i++) {
    // 和前一个不同就保留
    if (sortedArr[i] !== sortedArr[i - 1]) {
      newArr.push(sortedArr[i]);
    }
  }
  return newArr;
}

console.log(unique4(arr)); // [1,2,3,4,5]

.sort() 用于数组排序直接修改原数组,返回排序后的原数组引用

JS 引擎排序算法:主流为 Timsort,时间复杂度 (O(n\log n))


5. Map / Object 哈希表(性能最优之一)

思路:用 Map 记录元素是否出现过,O (n) 复杂度。

arduino 复制代码
function unique5(arr) {
  const map = new Map();
  const newArr = [];
  for (let item of arr) {
    // 不存在则存入
    if (!map.has(item)) {
      map.set(item, true);
      newArr.push(item);
    }
  }
  return newArr;
}

console.log(unique5(arr)); // [1,2,3,4,5]

Map键值对集合 ,键可以是任意类型(数字、字符串、对象等),键唯一,有序(按插入顺序


常用 MAP的API

arduino 复制代码
const map = new Map();

map.set(key, value)   // 添加/修改键值对
map.has(key)          // 判断键是否存在,返回布尔
map.get(key)          // 获取对应值
map.delete(key)       // 删除指定键
map.clear()           // 清空
map.size              // 获取元素个数

结合去重的原理

  1. 遍历原数组,把元素当作 Mapkey
  2. 每次先用 map.has(item) 判断是否已存在
  3. 不存在则存入 Map + 推入结果数组,利用Key 唯一性去重

特点

  1. 查询、插入效率极高,近似 (O(1)),整体遍历 (O(n))
  2. 可以正确识别 NaN、不同引用的对象(优于普通 Object)
  3. 有序,保留元素原始插入顺序
  4. 额外开辟哈希空间,空间复杂度 (O(n))

6. Set 数据结构(ES6 最简洁一行)

思路:Set 天生不允许重复,再转回数组。

javascript 复制代码
function unique6(arr) {
  // 一行搞定
  return [...new Set(arr)];
}

// 或简写
// const unique6 = arr => [...new Set(arr)];

console.log(unique6(arr)); // [1,2,3,4,5]

Set元素集合 ,特点:元素唯一、不重复、有序(插入顺序) ,是JS专为去重场景设计的数据结构。

常用 API

arduino 复制代码
const set = new Set();

set.add(value)    // 添加元素
set.has(value)    // 判断是否存在
set.delete(value) // 删除元素
set.clear()       // 清空
set.size          // 元素个数

数组 ↔ Set 互转

js

javascript 复制代码
// 数组转 Set(自动去重)
new Set(arr)

// Set 转回数组(两种写法)
[...new Set(arr)]      // 扩展运算符
Array.from(new Set(arr))

去重原理

Set 底层基于哈希表,不允许存储重复值,数组传入瞬间自动剔除重复项,再转回数组即可。

特点

  1. 代码最简洁,一行完成去重
  2. 时间复杂度 (O(n)),性能优秀
  3. 支持 NaN 去重(传统 indexOf 做不到)
  4. 保留原始顺序,ES6+ 环境首选
  5. 无法直接获取下标,只适合单纯去重场景
相关推荐
zithern_juejin4 小时前
new 运算符
javascript
前端毕业班4 小时前
uniapp web 灵活控制 style scoped
前端·javascript·vue.js
张元清5 小时前
在 React 里写动画又不跟渲染周期较劲:useRafFn、useRafState、useFps、useDevicePixelRatio、useUpdate
前端·javascript·面试
甜味弥漫7 小时前
JavaScript 底层逻辑:从内存视角看原型与原型链
前端·javascript
咪饭只吃一小碗7 小时前
JS this 身世大揭秘:它到底该听谁的?
前端·javascript
周淳APP7 小时前
【前端八股第一弹】
开发语言·前端·javascript·react.js
SmartBoyW7 小时前
撕掉前端黑魔法外衣:用 C++/Java 指针思维硬核拆解 JS 原型链
前端·javascript
三乐2288 小时前
JS难点之:this怎么用
javascript
拾晚霞8 小时前
记录一下谷歌浏览器静默开启“本地网络访问权限(LNA)”的坑
javascript·chrome