优秀的编程知识分享平台

网站首页 > 技术文章 正文

JavaScript 数组去重方法总结(js 数组去重的四种方法)

nanyue 2025-05-05 17:54:43 技术文章 2 ℃

对象数组去重方法

基于对象唯一标识符去重

1. Map 结构 + 属性映射

const uniqueArr = Array.from(
  new Map(arr.map(item => [item.id, item])).values()
);

特点

  • 高效且简洁
  • 适用于对象有唯一标识符的场景(如 id)
  • 保留最后一个出现的对象

2. reduce + find/some 判断

const uniqueArr = arr.reduce((acc, cur) => {
  const exists = acc.some(item => item.id === cur.id);
  return exists ? acc : [...acc, cur];
}, []);

特点

  • 灵活,支持复杂逻辑
  • 性能较低(O(n^2))
  • 可自定义判断条件

基于对象内容哈希去重

1. JSON.stringify 序列化比较

const uniqueArr = arr.filter((item, index) => {
  const str = JSON.stringify(item);
  return index === arr.findIndex(obj => JSON.stringify(obj) === str);
});

特点

  • 简单,无需唯一属性
  • 仅适用于对象内容完全一致且顺序相同的场景
  • 无法处理属性顺序变化或嵌套对象中的引用差异

2. 自定义哈希函数

const hash = obj => `${obj.id}-${obj.name}`;
const uniqueArr = arr.filter((item, index) => 
  index === arr.findIndex(obj => hash(obj) === hash(item))
);

特点

  • 高度灵活,支持复杂对象结构
  • 需手动维护哈希逻辑
  • 可根据业务需求定制哈希规则

普通值数组去重方法

ES6+ 高效方法

1. Set 数据结构

const uniqueArr = [...new Set(arr)]; 
// 或
const uniqueArr = Array.from(new Set(arr));

特点

  • 代码简洁
  • 时间复杂度为 O(n)
  • 自动处理 NaN(认为 NaN === NaN)

2. Map 数据结构

const map = new Map();
arr.forEach(item => map.set(item, true));
const uniqueArr = Array.from(map.keys());

特点

  • 适用于复杂场景
  • 性能与 Set 相近
  • 可保留特定顺序

ES5 兼容方法

1. filter + indexOf

const uniqueArr = arr.filter((item, index) => arr.indexOf(item) === index);

特点

  • 兼容性好
  • 无法识别 NaN(两个 NaN 会被视为不重复)
  • 性能中等

2. reduce 累加

const uniqueArr = arr.reduce((acc, cur) => 
  acc.includes(cur) ? acc : [...acc, cur], []);

特点

  • 逻辑清晰
  • 时间复杂度为 O(n^2)
  • 支持链式调用

3. 对象键值对法

const obj = {};
const uniqueArr = [];
arr.forEach(item => {
  if (!obj[item]) {
    obj[item] = true;
    uniqueArr.push(item);
  }
});

特点

  • 性能较高(O(n))
  • 会将 1 和 "1" 视为相同
  • 不适用于复杂数据类型

方法对比与选择建议

对象数组去重

方法

适用场景

优点

缺点

Map + 唯一标识符

对象有明确唯一属性

高效、代码简洁

依赖唯一属性

reduce + find/some

无唯一属性但需动态判断

灵活

性能较低

JSON.stringify

对象内容完全一致

简单

不适用动态属性

自定义哈希函数

需要自定义规则

高度灵活

需维护哈希逻辑

普通值数组去重

方法

适用场景

优点

缺点

Set

ES6+ 环境

高效(O(n))

无法区分 NaN

filter + indexOf

兼容旧浏览器

无需依赖 ES6

无法处理 NaN

对象键值对法

高性能需求

O(n)

混淆类型

reduce

逻辑清晰

支持链式调用

性能较低

示例场景

对象数组去重

// 用户列表去重(基于 userId)
const users = [
  { userId: 1, name: 'Alice' },
  { userId: 2, name: 'Bob' },
  { userId: 1, name: 'Alice' } // 重复项
];
const uniqueUsers = Array.from(new Map(users.map(u => [u.userId, u])).values());

普通值数组去重

// 处理包含 NaN 的数组
const arr = [NaN, 1, NaN, 2];
const uniqueArr = Array.from(new Set(arr)); // [NaN, 1, 2]

注意事项

  1. 对象去重需根据业务需求选择策略,优先使用 Map 或唯一属性法提升性能
  2. 对于复杂场景,可结合哈希函数或工具库(如 lodash.uniqBy)简化实现
  3. 普通值去重中,Set 方法在 ES6+ 环境下是最优选择
  4. 兼容旧浏览器时,filter + indexOf 或对象键值对法是较好选择
  5. 注意不同类型值的处理(如数字 1 和字符串 "1")
  6. NaN 的处理在不同方法中表现不同,需特别注意

Tags:

最近发表
标签列表