数组去重,是一个老生常谈的问题了,在各厂的面试中也会有所提及,接下来就来细数一下各种数组去重的方式吧;

对于以下各种方式都统一命名为 unique,公用代码如下:

// 生成一个包含100000个[0,50000)随机数的数组
var arr = [];
for(var i = 0; i < 100000; i++) {arr.push(Math.floor(Math.random() * 50000));
}
Array.prototype.unique = function() { // 算法 };
console.log(arr.unique());  // 一个已经去重的数组
复制代码

1、双重遍历

双重遍历的实现主要是通过两次遍历的对比,生成一个新的,不含重复数据的数组;

其实现方式有如下两种:

/** 第一种实现方式:* 对数组的每个元素在推入新数组之前与新数组中每个元素比较,如果没有相同值则推入*/
Array.prototype.unique = function() {if(!Array.isArray(this)) throw new Error('Type Error: The target should be an Array!');var newArray = [], isRepeat;for(var i = 0, length = this.length; i < length; i++) {isRepeat = false;for(var j = 0, newLength = newArray.length; j < newLength; j++) {if(this[i] === newArray[j]) {isRepeat = true;break;}}if(!isRepeat) newArray.push(this[i]);}return newArray;
};
/** 第二种实现方式* 将数组的每个元素与其后面所有元素做遍历对比,若有相同的值,则不推入新数组,*/
Array.prototype.unique = function() {if(!Array.isArray(this)) throw new Error('Type Error: The target should be an Array!');var newArray = [], isRepeat;for(var i = 0, length = this.length; i < length; i++) {isRepeat = false;for(var j = i + 1; j < length; j++) {if(this[i] === this[j]) {isRepeat = true;break;}}if(!isRepeat) newArray.push(this[i]);}return newArray;
};// 实测耗时
// 方式一:2372 ms
// 方式二:4025 ms
复制代码

2、Array.prototype.indexOf()

通过 indexOf 方法查询值在数组中的索引,并通过对索引的判断来实现去重;

主要实现方式有下面两种:

/*** 第一种实现方式* 结合数组的 filter 方法,将相同值的第一个合并到一个新的数组中返回* indexOf 检测到的索引为出现当前值的第一个位置* 若 indexOf 检测到的索引和当前值索引不相等则说明前面有相同的值*/
Array.prototype.unique = function() {if(!Array.isArray(this)) throw new Error('Type Error: The target should be an Array!');return this.filter(function(item, index, array) {return array.indexOf(item) === index;});
};
/*** 第二种实现方式* 对数组进行遍历,并将每个元素在新数组中匹配* 若新数组中无该元素,则插入*/
Array.prototype.unique = function() {if(!Array.isArray(this)) throw new Error('Type Error: The target should be an Array!');var newArray = [];this.forEach(function(item) {if(newArray.indexOf(item) === -1) newArray.push(item);});return newArray;
};// 实测耗时
// 方式一:3972 ms
// 方式二:2650 ms
复制代码

3、Array.prototype.sort()

sort 方法可对数组进行排序,此时相同的值就会被排到一起,然后通过相邻元素比较就可知是否有相同值了;

举个栗子:

/*** 第一种实现方式* 先将数组通过 sort 排序* 再遍历数组,将每个元素与其前面一个元素比较* 若值不同则表示该元素第一次出现,则插入到新数组*/
Array.prototype.unique = function() {if(!Array.isArray(this)) throw new Error('Type Error: The target should be an Array!');var newArray = [];this.sort();for(var i = 0, length = this.length; i < length; i++) {if(this[i] !== this[i - 1]) newArray.push(this[i]);}return newArray;
};
/*** 第二种实现方式* 先将数组通过 sort 排序* 再遍历数组,将每个元素与插入到新数组中的最后一个元素比较* 若值不同则表示该元素第一次出现,则插入到新数组*/
Array.prototype.unique = function() {if(!Array.isArray(this)) throw new Error('Type Error: The target should be an Array!');var newArray = [];this.sort();for(var i = 0, length = this.length; i < length; i++) {if(this[i] !== newArray[newArray.length - 1]) newArray.push(this[i]);}return newArray;
};// 实测耗时
// 方式一:105 ms
// 方式二:112 ms
复制代码

由于方式二在每次比较的时候需要重新计算一次 newArray.length 故会稍微比方式一慢一点;

3、Array.prototype.includes(searchElm, fromIndex)

该方法判断数组中是否存在指定元素

参数:

  • searchElm:需要查找的元素
  • fromIndex:开始查找索引位置(若未负值,则从 array.length - fromIndex 位置开始查找

返回值:

  • Boolean:数组中是否存在该元素
/*** 实现方式* 遍历数组,通过 includes 判断每个值在新数组中是否存在* 若不存在,则将值插入到新数组中*/
Array.prototype.unique = function() {if(!Array.isArray(this)) throw new Error('Type Error: The target should be an Array!');var newArray = [];this.forEach(function(item) {if(!newArray.includes(item)) newArray.push(item);});return newArray;
};// 实测耗时:2597 ms
复制代码

4、Array.prototype.reduce()

/*** 实现方式* 先将数组进行排序* 然后利用 reduce 迭代和累加的特性,将符合要求的元素累加到新数组并返回*/
Array.prototype.unique = function() {if(!Array.isArray(this)) throw new Error('Type Error: The target should be an Array!');return this.sort().reduce(function(newArr, curr) {if(newArr[newArr.length - 1] !== curr) newArr.push(curr);return newArr;}, []);
};// 实测耗时:127 ms
复制代码

5、对象的键值对

利用对象的 key 不能重复的特性来去重; 之前看到有人使用对象的键值对去重的时候,直接将数组的每个值设置为对象的 keyvalue 都为1,每出现一个相同的值时就 value++,这样既可以去重,又可以知道对应的值出现的次数,例如:

var array = ['a', 'b', 'c', 'a', 'a', 'c'];
var newArr = [], obj = {};
array.forEach(function(item) {if(obj[item]) {obj[item]++;} else {obj[item] = 1;newArr.push(item);}
});
console.log(newArr); // ["a", "b", "c"]
console.log(obj);    // {a: 3, b: 1, c: 2}
复制代码

咋一看好像很完美,可是仔细一想,会发现有以下几点原因:

  • 若数组的值中出现了隐式类型转换成字符串后相等的值,则无法区分,例如 '1' 和 1;
  • 若数组中的值有对象,写成 key 之后都是 [object Object],无法区分;

解决方案:

若元素值的类型为 object,则通过 JSON.stringify 方法进行转换;

Array.prototype.unique = function() {if(!Array.isArray(this)) throw new Error('Type Error: The target should be an Array!');var newArr = [], obj = {};this.forEach(function(item) {if(!obj[typeof item + JSON.stringify(item)]) {obj[typeof item + JSON.stringify(item)] = 1;newArr.push(item);}});return newArr;
};// 实测耗时:142 ms
复制代码

6、Set

Set 对象的特性就是其中的值是唯一的,可利用该特性很便捷的处理数组去重的问题;

/*** 实现方式一* 将数组转换成 Set 对象* 通过 Array.from 方法将 Set 对象转换为数组*/
Array.prototype.unique = function() {if(!Array.isArray(this)) throw new Error('Type Error: The target should be an Array!');var set = new Set(this);return Array.from(set);
};// 实测耗时:45 ms/*** 实现方式二* 将数组转换成 Set 对象* 通过 Array.from 方法将 Set 对象转换为数组*/
Array.prototype.unique = function() {if(!Array.isArray(this)) throw new Error('Type Error: The target should be an Array!');return [...new Set(this)];
};// 实测耗时:65 ms
复制代码

由以上耗时结果可以看出:

  • filter, forEach 等方法都会对全数组进行遍历;
  • indexOf, for+break, includes 等方法会对数组遍历,在满足条件的地方跳出遍历

转载于:https://juejin.im/post/5b2612e36fb9a00e50312e2d

数组去重的各种方式对比相关推荐

  1. 数组去重实现的方式(越多越好)

    const arr = [1, 1, '1', 17, true, true, false, false, 'true', 'a', {}, {}]; 想要的结果 => [1, '1', 17, ...

  2. 数组去重的各种方法速度对比

    首先需要一个自动生成数组的函数 // 自动生成数组的函数function randomArr (n) {let arr = [];for (let i = 1; i <= n; i++) {ar ...

  3. c语言用hash方式数组去重,利用set实现去重

    最近读了一些有关于ES6的文章,觉得真是一个超级大的进步,就是不知道兼容性怎么样,鉴于我还在初学,先写个小例子练手,顺便时刻提醒自己要坚持学下去.未来的趋势肯定是替代es5没跑了. var arr=[ ...

  4. Java数组去重的多种方法,[Java教程]JavaScript常见的五种数组去重的方式

    [Java教程]JavaScript常见的五种数组去重的方式 0 2016-12-14 15:00:17 ▓▓▓▓▓▓ 大致介绍 JavaScript的数组去重问题在许多面试中都会遇到,现在做个总结 ...

  5. 2019.08.30数组去重的几种方法以及所需时间对比

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. php array 数组去重,更快的方式实现 PHP 数组去重

    如何学习PHP array_flip()定义和用法 array_flip() 函数返回一个反转后的数组,如果同一值出现了多次,则最后一个键名将作为它的值,所有其他的键名都将丢失. 如果原数组中的值的数 ...

  7. php 数组去重函数,【译】更快的方式实现PHP数组去重

    概述 使用PHP的array_unique()函数允许你传递一个数组,然后移除重复的值,返回一个拥有唯一值的数组.这个函数大多数情况下都能工作得很好.但是,如果你尝试在一个大的数组里使用array_u ...

  8. js实现数组去重的方式(7种)

    目录 JS数组去重的方式 1.利用Set()+Array.from() 2.利用两层循环+数组的splice方法 3.利用数组的indexOf方法 4.利用数组的includes方法 5.利用数组的f ...

  9. JavaScript数组去重的方式

    数组去重的意思就是去除数组中重复的元素,处理完后数组中所有的元素都是唯一的,本文介绍了在js中数组去重的5种方式,请往下看. 1. 利用Set对象 Set 对象 Set 对象允许你存储任何类型的唯一值 ...

最新文章

  1. 静态类和非静态类中静态变量
  2. linux 擦 日志,linux日志清除脚本(擦屁股必备)
  3. 安装MMCV和MMDET
  4. NIO详解(十一):线程间通信管道Pipe
  5. sql注入-union select
  6. Jquery函数大全 - 案例说明
  7. Storm任务提交过程及目录树介绍
  8. html jade文件,Jade模板
  9. IT技术人终究要走上管理职位吗?
  10. 3月国内网民地域分布12强:广东居首 江苏重回第二
  11. 查看 Oracle 是用spfile 启动还是 pfile 启动
  12. 跋山涉水 —— 深入 Redis 字典遍历
  13. Linux下部署MongoDB
  14. 31 GroupSock(AddressString)——live555源码阅读(四)网络
  15. CTFMON。exe
  16. 在Python中分词
  17. 如何打开asm文件(学习汇编语言)
  18. SAP 和 ERP 区别
  19. LeetCode——974.和可被K整除的子数组
  20. The Frog Prince (青蛙王子) and Hello Kitty (凯蒂猫)

热门文章

  1. c语言第四版课后答案第三章3.4,算法与数据结构C语言版课后习题答案(机械工业出版社)第3,4章 习题参考答案...
  2. php斯芬克斯,斯芬克斯之迷——ie私有属性haslayout的困扰
  3. Georgia and Bob POJ - 1704 阶梯Nim
  4. scrapy爬虫框架windows下的安装问题
  5. 【WIN10】WIN2D——基本圖形的繪製
  6. PHP javascript 值互相引用(不用刷新页面)
  7. 一个表单同时向两个页面传值
  8. Discuz!$_G变量的使用方法
  9. C#使用Cookie方法
  10. phpweb2.0 开发实战 ----- 配置虚拟主机