方法一

无需思考,我们可以得到 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算法中的排序、数组去重详细概述
# 迭代
# 组中
# 我们可以
# 遍历
# 可选
# 则可
# 排在
# 将原
# 的是
# 都是
# 进阶
# 放在
# 出了
# 第一个
# 也就
# 一是
# 出现在
# 还不
# 可以用
# 只需
相关文章:
网站制作的方法有哪些,如何将自己制作的网站发布到网上?
建站主机选购指南:核心配置与性价比推荐解析
如何用PHP快速搭建高效网站?分步指南
魔方云NAT建站如何实现端口转发?
建站之星手机一键生成:多端自适应+小程序开发快速建站指南
中山网站推广排名,中山信息港登录入口?
建站之星客服服务时间及联系方式如何?
高防服务器租用指南:配置选择与快速部署攻略
较简单的网站制作软件有哪些,手机版网页制作用什么软件?
利用JavaScript实现拖拽改变元素大小
如何在阿里云部署织梦网站?
如何快速生成橙子建站落地页链接?
如何用y主机助手快速搭建网站?
高端建站如何打造兼具美学与转化的品牌官网?
如何用已有域名快速搭建网站?
广平建站公司哪家专业可靠?如何选择?
广州顶尖建站服务:企业官网建设与SEO优化一体化方案
大型企业网站制作流程,做网站需要注册公司吗?
宝塔面板如何快速创建新站点?
如何快速搭建自助建站会员专属系统?
实现虚拟支付需哪些建站技术支撑?
如何用虚拟主机快速搭建网站?详细步骤解析
专业企业网站设计制作公司,如何理解商贸企业的统一配送和分销网络建设?
如何在香港服务器上快速搭建免备案网站?
c++23 std::expected怎么用 c++优雅处理函数错误返回【详解】
北京专业网站制作设计师招聘,北京白云观官方网站?
广州网站建站公司选择指南:建站流程与SEO优化关键词解析
网站制作多少钱一个,建一个论坛网站大约需要多少钱?
C#怎么创建控制台应用 C# Console App项目创建方法
如何用花生壳三步快速搭建专属网站?
家具网站制作软件,家具厂怎么跑业务?
网站建设设计制作营销公司南阳,如何策划设计和建设网站?
如何通过FTP空间快速搭建安全高效网站?
制作无缝贴图网站有哪些,3dmax无缝贴图怎么调?
建站主机是什么?如何选择适合的建站主机?
定制建站如何定义?其核心优势是什么?
香港服务器建站指南:外贸独立站搭建与跨境电商配置流程
c# 在高并发场景下,委托和接口调用的性能对比
如何通过建站之星自助学习解决操作问题?
武汉外贸网站制作公司,现在武汉外贸前景怎么样啊?
宁波免费建站如何选择可靠模板与平台?
如何在建站之星网店版论坛获取技术支持?
深圳企业网站制作设计,在深圳如何网上全流程注册公司?
如何快速上传自定义模板至建站之星?
C#如何使用XPathNavigator高效查询XML
头像制作网站在线制作软件,dw网页背景图像怎么设置?
建站之星如何助力企业快速打造五合一网站?
哪家制作企业网站好,开办像阿里巴巴那样的网络公司和网站要怎么做?
如何用美橙互联一键搭建多站合一网站?
建站之星×万网:智能建站系统+自助建站平台一键生成
*请认真填写需求信息,我们会在24小时内与您取得联系。