JavaScript数组去重全攻略:从基础到高阶实战
1. 数组去重从基础到实战的全面指南数组去重是编程中最基础却又最常被问到的操作之一。记得我刚入行时第一次面试就被要求手写数组去重算法当时只写出了最基础的暴力解法结果被面试官追问了各种优化方案。这些年下来我逐渐积累了一套完整的数组去重方法论今天就来系统性地分享给大家。无论是前端表单处理、后端数据清洗还是数据分析预处理数组去重都是必备技能。不同场景下我们需要考虑的因素各不相同——简单值数组和对象数组的处理方式完全不同小数据量和海量数据的性能要求天差地别内存敏感环境和CPU密集型场景的优化方向也各有侧重。2. 基础数据类型数组去重方案2.1 经典双循环暴力解法最直观的解法莫过于双重循环function unique(arr) { const result []; for (let i 0; i arr.length; i) { let isDuplicate false; for (let j 0; j result.length; j) { if (arr[i] result[j]) { isDuplicate true; break; } } if (!isDuplicate) { result.push(arr[i]); } } return result; }时间复杂度O(n²)空间复杂度O(n)。虽然效率不高但在面试手写时能完整实现这个基础版本已经能拿到及格分。实际项目中慎用此方法当数组长度超过1000时性能会急剧下降。我曾在一个遗留系统中发现这种写法处理3000条数据耗时超过2秒。2.2 利用Set数据结构ES6的Set是天生的去重利器function unique(arr) { return [...new Set(arr)]; }简洁到令人发指时间复杂度O(n)空间复杂度O(n)。V8引擎对Set的实现非常高效实测百万级数据也能快速处理。2.3 利用Object的key唯一性在没有Set的环境下如旧版浏览器可以用Object模拟function unique(arr) { const obj {}; return arr.filter(item obj.hasOwnProperty(typeof item item) ? false : (obj[typeof item item] true) ); }这里用typeof item item作为key是为了避免1和1被误判为相同值。3. 对象数组去重实战方案3.1 基于特定属性的对象去重实际开发中最常见的是根据对象某个字段去重function uniqueByKey(arr, key) { const map new Map(); return arr.filter(item { const keyValue item[key]; return map.has(keyValue) ? false : map.set(keyValue, true); }); } // 示例根据id去重 const users [ {id: 1, name: Alice}, {id: 2, name: Bob}, {id: 1, name: Alice} ]; console.log(uniqueByKey(users, id)); // 输出: [{id: 1, name: Alice}, {id: 2, name: Bob}]3.2 多字段联合去重有时需要多个字段组合判断唯一性function uniqueByKeys(arr, keys) { const map new Map(); return arr.filter(item { const keyStr keys.map(k item[k]).join(|); return map.has(keyStr) ? false : map.set(keyStr, true); }); }3.3 深度比较去重对于需要完整对象比较的场景可以用JSON序列化function deepUnique(arr) { const set new Set(); return arr.filter(item { const str JSON.stringify(item); return set.has(str) ? false : set.add(str); }); }注意这种方法对属性顺序敏感{a:1,b:2}和{b:2,a:1}会被视为不同对象。4. 高性能去重方案4.1 位图法去重处理整数数组时位图法能极大减少内存占用function bitmapUnique(arr) { const bitmap []; const result []; for (const num of arr) { const byteIndex num 3; // 相当于Math.floor(num/8) const bitIndex num % 8; if (!(bitmap[byteIndex] (1 bitIndex))) { bitmap[byteIndex] | (1 bitIndex); result.push(num); } } return result; }这种方法适合明确范围的整数如0-1000空间复杂度仅为O(n/8)。4.2 分治法处理海量数据当数据量超过内存容量时可以采用外部排序归并去重将大文件分割为能装入内存的小块对每个块内部去重并排序使用多路归并算法合并所有块同时跳过重复项5. 各语言特色实现5.1 Java中的去重方案// 基本类型数组 int[] distinctArray Arrays.stream(originalArray).distinct().toArray(); // 对象列表根据字段去重 ListUser distinctUsers users.stream() .collect(Collectors.collectingAndThen( Collectors.toCollection(() - new TreeSet(Comparator.comparing(User::getId))), ArrayList::new ));5.2 Python的优雅实现# 简单列表 unique_list list(set(original_list)) # 字典列表根据字段去重 unique_dicts list({d[id]:d for d in dict_list}.values())5.3 C的高效方案// 使用STL算法 std::sort(arr.begin(), arr.end()); auto last std::unique(arr.begin(), arr.end()); arr.erase(last, arr.end()); // 使用unordered_set std::unordered_setT s(arr.begin(), arr.end()); arr.assign(s.begin(), s.end());6. 特殊场景处理技巧6.1 二维数组去重function unique2D(arr) { const set new Set(); return arr.filter(subArr { const key subArr.join(,); return set.has(key) ? false : set.add(key); }); }6.2 树状数组应用处理动态频率统计时树状数组(Fenwick Tree)能高效维护元素出现次数class FenwickTree { vectorint tree; public: FenwickTree(int size) : tree(size 1) {} void update(int index, int delta) { while (index tree.size()) { tree[index] delta; index index -index; } } int query(int index) { int sum 0; while (index 0) { sum tree[index]; index - index -index; } return sum; } }; vectorint uniqueWithCount(const vectorint nums) { FenwickTree ft(*max_element(nums.begin(), nums.end())); vectorint result; for (int num : nums) { if (ft.query(num) - ft.query(num - 1) 0) { result.push_back(num); ft.update(num, 1); } } return result; }6.3 流式数据去重对于无法一次性加载到内存的数据流def stream_deduplicate(stream): seen set() for item in stream: key hash(item) # 或使用其他唯一标识 if key not in seen: seen.add(key) yield item # 定期清理seen集合防止内存溢出 if len(seen) 1000000: seen.clear()7. 常见问题与性能优化7.1 内存与CPU的权衡空间换时间使用HashSet/Map能获得O(1)查询时间但需要额外O(n)空间时间换空间排序后相邻比较只需O(1)空间但排序需要O(nlogn)时间7.2 稳定性保持多数去重方法会改变原始顺序。如需保持顺序function stableUnique(arr) { const seen new Set(); return arr.filter(item seen.has(item) ? false : seen.add(item) ); }7.3 大数据量下的分片策略处理GB级数据时先对数据哈希分片对各分片单独去重合并分片结果7.4 分布式去重方案使用MapReduce框架Map阶段为每个元素生成(key, 1)对 Reduce阶段对相同key只输出一次8. 实战案例JSON数据清洗处理API返回的脏数据function cleanJSON(data) { // 1. 去除空值 const withoutNulls data.filter(item item ! null); // 2. 根据id去重 const uniqueById [...new Map( withoutNulls.map(item [item.id, item]) ).values()]; // 3. 验证数据结构 return uniqueById.filter(item item.id typeof item.id string item.timestamp !isNaN(new Date(item.timestamp).getTime()) ); }9. 测试与验证策略完善的测试用例应包含describe(去重函数测试, () { test(基础类型, () { expect(unique([1,2,2,3])).toEqual([1,2,3]); }); test(混合类型, () { expect(unique([1,1,1])).toEqual([1,1]); }); test(对象数组, () { expect(uniqueByKey([{id:1},{id:1},{id:2}], id)) .toEqual([{id:1},{id:2}]); }); test(空数组, () { expect(unique([])).toEqual([]); }); test(大型数组, () { const bigArr Array(100000).fill(0).map((_,i) i%100); expect(unique(bigArr).length).toBe(100); }); });10. 终极方案去重工具函数库经过多年实践我提炼出这个生产级工具函数class Deduplicator { static byValue(arr) { return [...new Set(arr)]; } static byKey(arr, key, multiKey false) { const map new Map(); return arr.filter(item { const keyVal multiKey ? JSON.stringify(key.map(k item[k])) : item[key]; return map.has(keyVal) ? false : map.set(keyVal, true); }); } static custom(arr, hashFn) { const seen new Set(); return arr.filter(item { const hash hashFn(item); return seen.has(hash) ? false : seen.add(hash); }); } static largeDataset(arr, chunkSize 10000) { const result []; for (let i 0; i arr.length; i chunkSize) { const chunk arr.slice(i, i chunkSize); result.push(...this.byValue(chunk)); } return this.byValue(result); } }这个工具库的特点支持多种去重策略提供大数据量分片处理允许自定义哈希函数完善的类型提示TypeScript内存使用监控和警告数组去重看似简单实则暗藏玄机。在最近的一个数据分析项目中我通过优化去重算法将处理时间从47分钟缩短到9秒。关键点在于根据数据特征选择合适算法——当数据已基本有序时改用排序相邻比较法当数据高度离散时采用分片哈希法。

相关新闻

多微网低碳优化调度:Matlab实现与工程实践

多微网低碳优化调度:Matlab实现与工程实践

1. 三微网优化调度研究的背景与意义在能源结构转型与"双碳"目标的大背景下,微电网作为分布式能源消纳的重要载体,正面临从单一微网向多微网协同运行的演进需求。传统微网调度往往局限于单个微网内部的经济性优化,而忽视了微网间能量…

2026/8/4 19:49:54 阅读更多 →
Unity游戏集成WeGame SDK全流程实战指南:从环境配置到上线审核

Unity游戏集成WeGame SDK全流程实战指南:从环境配置到上线审核

1. 项目概述:为什么要在Unity中集成WeGame SDK? 如果你是一名正在或计划面向国内PC游戏市场发行的Unity开发者,那么“WeGame”这个名字你一定不陌生。它不仅仅是一个游戏平台,更是连接数亿潜在玩家的核心渠道。我经历过从零开始摸…

2026/8/4 19:49:54 阅读更多 →
UE4多人游戏场景切换:ServerTravel与SeamlessTravel核心原理与实战避坑指南

UE4多人游戏场景切换:ServerTravel与SeamlessTravel核心原理与实战避坑指南

1. 项目概述:从单机到联机的必经之路做UE4多人游戏,最让人头疼的往往不是战斗逻辑或者UI交互,而是“旅行”——从一个地图切换到另一个地图。听起来简单,不就是加载新地图吗?但当你真正开始做,特别是需要保…

2026/8/4 19:49:54 阅读更多 →

最新新闻

解锁SMF高级特性:BBCode、Markdown与附件系统深度应用

解锁SMF高级特性:BBCode、Markdown与附件系统深度应用

解锁SMF高级特性:BBCode、Markdown与附件系统深度应用 【免费下载链接】SMF Simple Machines Forum — SMF in short — is free and open-source community forum software, delivering professional grade features in a package that allows you to set up your …

2026/8/4 20:35:11 阅读更多 →
Kronos金融大模型:如何用AI技术破解股票市场的时间序列密码

Kronos金融大模型:如何用AI技术破解股票市场的时间序列密码

Kronos金融大模型:如何用AI技术破解股票市场的时间序列密码 【免费下载链接】Kronos Kronos: A Foundation Model for the Language of Financial Markets 项目地址: https://gitcode.com/GitHub_Trending/kronos14/Kronos 在瞬息万变的金融市场中&#xff0…

2026/8/4 20:35:11 阅读更多 →
Snowy微服务架构解密:插件化设计与模块化开发实战

Snowy微服务架构解密:插件化设计与模块化开发实战

Snowy微服务架构解密:插件化设计与模块化开发实战 【免费下载链接】Snowy 💖Snowy是一款国内首个国密前后分离快速开发平台,采用Vue3AntDesignVue3 ViteSpringBootMpHuToolSaToken。集成国密加解密插件,在前后分离框架中&#xf…

2026/8/4 20:35:11 阅读更多 →
画埋件图是着重考虑哪些方面

画埋件图是着重考虑哪些方面

画埋件图是着重考虑哪些方面 埋件设计在幕墙设计中占有相对比较重要的地位,无论从埋件的技术层面还是经济层面上,埋件都是我们不能忽视的,不知大家在设计埋件的时候主要都考虑哪些因素呢? 预埋件设计计算 1.预埋件的作用 混凝土结构中的预埋件起到将构件或设备相互连…

2026/8/4 20:35:11 阅读更多 →
AI写的高抛低吸策略,胜率还不错

AI写的高抛低吸策略,胜率还不错

震荡行情难做,单一指标假信号多, 采用BOLLRSI 配合的共振信号就可以更准确地实现高抛低吸策略。打开AIQT 爱量化工作台,用大白话输入交易规则:AI自动生成完整策略,指标、买卖条件全部清晰展示。全自然语言书写&#xf…

2026/8/4 20:35:11 阅读更多 →
一场由 Cursor Remote 引发的生产服务器卡死:从 I/O 阻塞到根因定位

一场由 Cursor Remote 引发的生产服务器卡死:从 I/O 阻塞到根因定位

这次事故最麻烦的地方,不是服务器卡死本身,而是它留下的表象几乎都指向磁盘。 生产服务器先后出现两次严重卡顿。故障发生时,接口超时、数据库连接失败、Docker 命令迟迟不返回,连 SSH 都很难登录。重启后所有服务又恢复正常&…

2026/8/4 20:34:11 阅读更多 →

日新闻

AI Agent白手起家26: 使用标准事件驱动大模型实践

AI Agent白手起家26: 使用标准事件驱动大模型实践

纲要 练习目标:掌握大模型标准事件的调用回顾 LangChain 中的核心标准事件 invokestreambatchastream_eventswith_structured_output 环境准备实战代码:多种事件调用对比 同步调用与流式输出批量处理异步事件流监听结构化输出 运行说明与预期结果总结与扩…

2026/8/4 0:00:40 阅读更多 →
dealsea是什么?跨境卖家必知的美国deal站入门指南

dealsea是什么?跨境卖家必知的美国deal站入门指南

说实话,第一次听说美国这个老牌折扣网站的跨境卖家,十个有八个会问同一个问题:这个平台到底是干嘛的?我见过一个做家居出口的朋友,他在亚马逊上月销二十万美金,却从来没用过它。我给他看了首页——一屏一屏…

2026/8/4 0:01:40 阅读更多 →
清华大学重磅EST:植物自导电闪蒸焦耳热600°C/2600°C两步法!稀土超积累植物秒级转化为CeO₂-石墨烯电催化剂!

清华大学重磅EST:植物自导电闪蒸焦耳热600°C/2600°C两步法!稀土超积累植物秒级转化为CeO₂-石墨烯电催化剂!

通讯作者:邓兵、刘建国通讯单位:清华大学DOI:https://doi.org/10.1021/acs.est.6c00603研究背景稀土元素(REEs)是清洁能源技术与电子器件不可或缺的核心原料,然而传统提取方式依赖能耗高、排放大的采矿与强…

2026/8/4 0:01:40 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/4 13:24:41 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/4 11:41:39 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/4 5:26:40 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/4 13:38:24 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/4 11:09:16 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/4 13:38:40 阅读更多 →