JavaScript数组去重的6个方法
方法一
无需思考,我们可以得到 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]; (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 方法,和我们上面说的方法一异曲同工。
文章来源于:http://www.qdfuns.com/notes/23908/df7b338047a8c9fefcca8c2168b2f0cd.html
JavaScript数组去重的6个方法的更多相关文章
- JavaScript数组去重的几种方法
这个老问题,网上普遍都有了,为什么要再写一遍呢,主要是为了记个笔记... 遍历时搜索结果数组 思路很明确,如下 新建一个数组存放结果 循环遍历原数组,对于每一个元素,在结果数组中搜索是否存在 若不存在 ...
- javascript数组去重的三种常用方法,及其性能比较
在进行数组操作时往往会遇到去掉重复项的问题,下面简单介绍下数组去重的方法,以及其执行效率 方法一 采用两次循环 原理:拿当前的和他后面的比,如果后面的有重复的就干掉 ...
- JavaScript数组去重的10种方法
「数组去重」的确是个老生常谈的问题了,但是你真正的掌握了吗?平时开发中是不是用最简单粗暴的方法来去重?注意到它的性能问题了吗?当面试官对你回答的四个去重方法都不满意时你可以想出更简单且性能能更好的方法 ...
- JavaScript数组去重的四种方法
今天,洗澡的想一个有趣的问题,使用js给数组去重,我想了四种方法,虽然今天的任务没有完成,5555: 不多说,po代码: //方法一:简单循环去重 Array.prototype.unique1 ...
- [转] JavaScript数组去重(12种方法)
数组去重,一般都是在面试的时候才会碰到,一般是要求手写数组去重方法的代码.如果是被提问到,数组去重的方法有哪些?你能答出其中的10种,面试官很有可能对你刮目相看.在真实的项目中碰到的数组去重,一般都是 ...
- javascript数组去重的4个方法
Array.prototype.unique1 = function(){//有局限性,1,“1”的情况会被去重,因为存入临时对象时,数组中的值被统一转换成了字符串 var obj = {},newA ...
- javascript数组去重的4个方法(转)
原文地址:http://blog.csdn.net/chengxuyuan20100425/article/details/8497277 面试前端必须准备的一个问题:怎样去掉Javascript的A ...
- javascript数组去重的两个方法
方法一: 创建一个临时数组,判断目标数组中每个元素是否在临时数组中,如果不在就添加进临时数组,最后return临时数组 <script> var arr=[1,2,3,4,5,1,2,3, ...
- javascript数组去重的3种方法
前言:这是笔者学习之后自己的理解与整理.如果有错误或者疑问的地方,请大家指正,我会持续更新! javascript数组去重 <!DOCTYPE html> <html> < ...
随机推荐
- 待解决输入istream_iterator
山寨版 istream_iterator 输入 第一行是整数t,表示有t组数据,每组数据一行,三个整数加两个字符串.字符串是不含空格的. 输出 对每组数据,输出二行,在第一行输出第一个数,第二行原样输 ...
- 微信小程序开发记录
顶栏banner代码 /**app.wxss**/ .container { height: 100%; display: flex; flex-direction: column; align-it ...
- ifconfig相关参数及用法说明
一.ifconfig ifconfig 主要是可以手动启动.观察与修改网络接口的相关参数,可以修改的参数很多,包括 IP 参数以及 MTU 等都可以修改,它的语法如下: [root@linux ~]# ...
- CAN总线相关的几个gitlab代码
https://github.com/brtiberio/ATV71_CANopen.git https://github.com/linux-can/can-utils.git https://gi ...
- Centos7环境下etcd集群的搭建
Centos7环境下etcd集群的搭建 一.简介 "A highly-available key value store for shared configuration and servi ...
- python学习第3天
03 int 十进制与二进制之间的转换04 bool 05 str python中凡是用引号引起来的都是字符串 1,存储相对少量的数据. 2,描述信息. 1,bool str int 三者之间的转换 ...
- 数据库之删除表数据drop、truncate和delete的用法
数据库中删除表数据的关键字,最常用的可能就是delete了,另外其实还有drop和truncate两个关键字. 老大:drop 命令格式:drop table tb ---tb表示数据表的名字,下 ...
- 如何将本地项目上传到Github
看了这篇文章觉得写的很详细很适合初学者 提供给大家参考下. http://blog.csdn.net/zamamiro/article/details/70172900 注意如果第二次git pus ...
- form表单公用
<?php /** * 后台总控制器 */ namespace app\common\controller; use think\Controller; use app\common\servi ...
- 经典JS闭包面试题(来理解闭包)(转)
转载地址:http://www.cnblogs.com/xxcanghai/p/4991870.html 先看代码: function fun(n,o) { console.log(o) return ...