JavaScript数组去重的6个方法

发布时间 - 2026-01-10 22:41:55    点击率:

方法一

无需思考,我们可以得到 O(n^2) 复杂度的解法。定义一个变量数组 res 保存结果,遍历需要去重的数组,如果该元素已经存在在 res 中了,则说明是重复的元素,如果没有,则放入 res 中。

 function unique(a) {
 var res = [];
 for (var i = 0, len = a.length; i < len; i++) {
 var item = a[i];
 for (var j = 0, jLen = res.length; j < jLen; j++) {
 if (res[j] === item)
 break;
 }
 if (j === jLen)
 res.push(item);
 }
 return res;
}
var a = [1, 1, '1', '2', 1];
var ans = unique(a);
console.log(ans); // => [1, "1", "2"]

代码非常简单,那么是否能更简洁些?如果不考虑浏览器兼容,我们可以用 ES5 提供的 Array.prototype.indexOf 方法来简化代码。

function unique(a) {
 var res = [];
 for (var i = 0, len = a.length; i < len; i++) {
 var item = a[i];
 (res.indexOf(item) === -1) && res.push(item);
 }
 return res;
}
var a = [1, 1, '1', '2', 1];
var ans = unique(a);
console.log(ans); // => [1, "1", "2"]

既然用了 indexOf,那么不妨再加上 filter。

function unique(a) {
 var res = a.filter(function(item, index, array) {
 return array.indexOf(item) === index;
 });
 return res;
}
var a = [1, 1, '1', '2', 1];
var ans = unique(a);
console.log(ans); // => [1, "1", "2"]

方法二

法一是将原数组中的元素和结果数组中的元素一一比较,我们可以换个思路,将原数组中重复元素的最后一个元素放入结果数组中。

function unique(a) {
 var res = a.filter(function(item, index, array) {
 return array.indexOf(item) === index;
 });
 return res;
}
var a = [1, 1, '1', '2', 1];
var ans = unique(a);
console.log(ans); // => [1, "1", "2"]

虽然复杂度还是 O(n^2),但是可以看到结果不同,1 出现在了数组最后面,因为结果数组取的是元素最后一次出现的位置。

方法三(sort)

如果笔试面试时只答出了上面这样 O(n^2) 的方案,可能还不能使面试官满意,下面就来说几种进阶方案。

将数组用 sort 排序后,理论上相同的元素会被放在相邻的位置,那么比较前后位置的元素就可以了。

function unique(a) {
 return a.concat().sort().filter(function(item, pos, ary) {
 return !pos || item != ary[pos - 1];
 });
}
var a = [1, 1, 3, 2, 1, 2, 4];
var ans = unique(a);
console.log(ans); // => [1, 2, 3, 4]

但是问题又来了,1 和 "1" 会被排在一起,不同的 Object 会被排在一起,因为它们 toString() 的结果相同,所以会出现这样的错误:

function unique(a) {
 return a.concat().sort().filter(function(item, pos, ary) {
 return !pos || item != ary[pos - 1];
 });
}
var a = [1, 1, 3, 2, 1, 2, 4, '1'];
var ans = unique(a);
console.log(ans); // => [1, 2, 3, 4]

当然你完全可以针对数组中可能出现的不同类型,来写这个比较函数。不过这似乎有点麻烦。

方法四 (object)

用 JavaScript 中的 Object 对象来当做哈希表,这也是几年前笔试时的解法,跟 sort 一样,可以去重完全由 Number 基本类型组成的数组。

function unique(a) {
 var seen = {};
 return a.filter(function(item) {
 return seen.hasOwnProperty(item) ? false : (seen[item] = true);
 });
}
var a = [1, 1, 3, 2, 1, 2, 4];
var ans = unique(a);
console.log(ans); // => [1, 3, 2, 4]

还是和方法三一样的问题,因为 Object 的 key 值都是 String 类型,所以对于 1 和 "1" 无法分别,我们可以稍微改进下,将类型也存入 key 中。

function unique(a) {
 var ret = [];
 var hash = {};
 for (var i = 0, len = a.length; i < len; i++) {
 var item = a[i];
 var key = typeof(item) + item;
 if (hash[key] !== 1) {
 ret.push(item);
 hash[key] = 1;
 }
 }
 return ret;
}
var a = [1, 1, 3, 2, '4', 1, 2, 4, '1'];
var ans = unique(a);
console.log(ans); // => [1, 3, 2, "4", 4, "1"]

虽然解决了讨厌的 1 和 "1" 的问题,但是还有别的问题!

function unique(a) {
 var ret = [];
 var hash = {};
 for (var i = 0, len = a.length; i < len; i++) {
 var item = a[i];
 var key = typeof(item) + item;
 if (hash[key] !== 1) {
 ret.push(item);
 hash[key] = 1;
 }
 }
 return ret;
}
var a = [{name: "hanzichi"}, {age: 30}, new String(1), new Number(1)];
var ans = unique(a);
console.log(ans); // => [Object, String]

但是如果数组元素全部是基础类型的 Number 值,键值对法应该是最高效的!

方法五 (ES6)

ES6 部署了 Set 以及 Array.from 方法,太强大了!如果浏览器支持,完全可以这样:

function unique(a) {
 return Array.from(new Set(a));
}
var a = [{name: "hanzichi"}, {age: 30}, new String(1), new Number(1)];
var ans = unique(a);
console.log(ans); // => [Object, Object, String, Number]

_.unique

最后来看看 underscore 对此的实现方式,underscore 将此封装到了 _.unique 方法中,调用方式为 _.unique(array, [isSorted], [iteratee])。其中第一个参数是必须的,是需要去重的数组,第二个参数可选,如果数组有序,则可以传入布尔值 true,第三个参数可选,如果需要对数组迭代的结果去重,则可以传入一个迭代函数。而数组元素去重是基于 === 运算符的。

其实很简单,underscore 中的实现方式和上面的方法一相似。

我们来看它的核心代码:

for (var i = 0, length = getLength(array); i < length; i++) {
 var value = array[i],
 // 如果指定了迭代函数
 // 则对数组每一个元素进行迭代
 computed = iteratee ? iteratee(value, i, array) : value;
 // 如果是有序数组,则当前元素只需跟上一个元素对比即可
 // 用 seen 变量保存上一个元素
 if (isSorted) {
 // 如果 i === 0,则直接 push
 // 否则比较当前元素是否和前一个元素相等
 if (!i || seen !== computed) result.push(value);
 // seen 保存当前元素,供下一次对比
 seen = computed;
 } else if (iteratee) {
 // 如果 seen[] 中没有 computed 这个元素值
 if (!_.contains(seen, computed)) {
 seen.push(computed);
 result.push(value);
 }
 } else if (!_.contains(result, value)) { 
 // 如果不用经过迭代函数计算,也就不用 seen[] 变量了
 result.push(value);
 }
}

外面的循环遍历数组元素,对于每个元素,如果数组有序,则和前一个元素比较,如果相同,则已经出现过,不加入到结果数组中,否则则加入。而如果有迭代函数,则计算传入迭代函数后的值,对值去重,调用 .contains 方法,而该方法的核心就是调用.indexOf 方法,和我们上面说的方法一异曲同工。

 以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!


# js  # 数组去重  # 数组去重的方法  # javascript  # JavaScript数组去重的两种方法推荐  # JavaScript数组去重的五种方法  # js数组去重的5种算法实现  # javascript数组去重的六种方法汇总  # js数组去重的方法汇总  # JS数组返回去重后数据的方法解析  # js数组去重的hash方法  # js 数组去重的四种实用方法  # js数组去重的常用方法总结  # js实现数组去重、判断数组以及对象中的内容是否相同  # js算法中的排序、数组去重详细概述  # 迭代  # 组中  # 我们可以  # 遍历  # 可选  # 则可  # 排在  # 将原  # 的是  # 都是  # 进阶  # 放在  # 出了  # 第一个  # 也就  # 一是  # 出现在  # 还不  # 可以用  # 只需 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 详解Oracle修改字段类型方法总结  详解MySQL数据库的安装与密码配置  深圳网站制作公司好吗,在深圳找工作哪个网站最好啊?  高端网站建设与定制开发一站式解决方案 中企动力  Windows Hello人脸识别突然无法使用  Laravel的Blade指令怎么自定义_创建你自己的Laravel Blade Directives  Laravel如何处理跨站请求伪造(CSRF)保护_Laravel表单安全机制与令牌校验  如何挑选最适合建站的高性能VPS主机?  香港网站服务器数量如何影响SEO优化效果?  Laravel怎么使用Intervention Image库处理图片上传和缩放  Laravel Pest测试框架怎么用_从PHPUnit转向Pest的Laravel测试教程  Laravel如何理解并使用服务容器(Service Container)_Laravel依赖注入与容器绑定说明  中山网站推广排名,中山信息港登录入口?  微博html5版本怎么弄发超话_超话进入入口及发帖格式要求【教程】  Win11怎么恢复误删照片_Win11数据恢复工具使用【推荐】  网站制作免费,什么网站能看正片电影?  Laravel怎么配置S3云存储驱动_Laravel集成阿里云OSS或AWS S3存储桶【教程】  Win11怎么查看显卡温度 Win11任务管理器查看GPU温度【技巧】  如何在建站主机中优化服务器配置?  js实现点击每个li节点,都弹出其文本值及修改  详解免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七)  Linux系统命令中tree命令详解  Laravel如何集成Inertia.js与Vue/React?(安装配置)  Laravel如何实现一对一模型关联?(Eloquent示例)  Laravel如何发送邮件_Laravel Mailables构建与发送邮件的简明教程  香港服务器网站推广:SEO优化与外贸独立站搭建策略  Laravel如何实现RSS订阅源功能_Laravel动态生成网站XML格式订阅内容【教程】  如何在Ubuntu系统下快速搭建WordPress个人网站?  LinuxShell函数封装方法_脚本复用设计思路【教程】  HTML透明颜色代码怎么让下拉菜单透明_下拉菜单透明背景指南【技巧】  如何在万网自助建站平台快速创建网站?  如何在云虚拟主机上快速搭建个人网站?  如何在万网开始建站?分步指南解析  如何续费美橙建站之星域名及服务?  C++时间戳转换成日期时间的步骤和示例代码  Laravel怎么定时执行任务_Laravel任务调度器Schedule配置与Cron设置【教程】  QQ浏览器网页版登录入口 个人中心在线进入  javascript如何操作浏览器历史记录_怎样实现无刷新导航  Android滚轮选择时间控件使用详解  Laravel的契約(Contracts)是什么_深入理解Laravel Contracts与依赖倒置  如何用y主机助手快速搭建网站?  油猴 教程,油猴搜脚本为什么会网页无法显示?  laravel怎么使用数据库工厂(Factory)生成带有关联模型的数据_laravel Factory生成关联数据方法  如何快速搭建安全的FTP站点?  Laravel如何集成微信支付SDK_Laravel使用yansongda-pay实现扫码支付【实战】  Laravel事件和监听器如何实现_Laravel Events & Listeners解耦应用的实战教程  网站建设保证美观性,需要考虑的几点问题!  ai格式如何转html_将AI设计稿转换为HTML页面流程【页面】  Laravel N+1查询问题如何解决_Eloquent预加载(Eager Loading)优化数据库查询  详解jQuery中基本的动画方法