以 var arr = [1,2,3,1]; 作为测试用例  

方法一:双循环   (时间复杂度比较高,性能一般。)

A、(1)

 function unique(arr) {
var newArr = [];
var len = arr.length;
var isRepeat; for(var i=0; i<len; i++) { //第一次循环
isRepeat = false;
for(var j=i+1; j<len; j++) { //第二次循环
if(arr[i] === arr[j]){
isRepeat = true;
break;
}
}
if(!isRepeat){
newArr.push(arr[i]);
}
}
return newArr;

输出 newArr 结果:

B、(2)

 function unique(arr) {
var newArr = [];
var len = arr.length;
for(var i=0; i<len; i++){ // 第一次循环
for(var j=i+1; j<len; j++){ // 第二次循环
if(arr[i] === arr[j]){
j = ++i;
}
}
newArr.push(arr[i]);
}
return newArr;
}

输出 newArr 结果:

tip:  j = ++ i; 等价于 j = j+1; i = i+1;

整体思路就是 如果是重复元素,则跳过重复元素,不对其进行 push 操作。

方法二:Array.prototype.indexOf()

A、(3)

 function unique(arr) {
return arr.filter(function(item, index){ //item 表示数组中的每个元素,index 是每个元素的出现位置。
return arr.indexOf(item) === index; // indexOf 返回第一个索引值
});
}

输出 新 arr 结果:

tip:var new_arrary = arr.filter(callback[, thisArg]);  其中 callback 用来测试数组的每个元素的函数。调用时使用参数 element, index, array。
返回true表示保留该元素(通过测试),false则不保留。thisArg可选,执行 callback 时的用于 this 的值。

整体思路就是索引不是第一个索引,说明是重复值。

B、(4)

 function unique(arr) {
var newArr = [];
arr.forEach(function(item){ //一次循环,item 即为数组中的每一项
if(newArr.indexOf(item) === -1){
newArr.push(item);
}
});
return newArr;
}

输出 newArr 结果:

方法三:Array.prototype.sort()

A、(5)

 function unique(arr) {
var newArr = [];
arr.sort();
for(var i = 0; i < arr.length; i++){
if( arr[i] !== arr[i+1]){
newArr.push(arr[i]);
}
}
return newArr;
}

输出 newArr 结果:

tip: 整体思路就是 先进行排序,然后比较相邻元素。

B、(6)

 function unique(arr) {
var newArr = [];
arr.sort();
var newArr = [arr[0]];
for(var i = 1; i < arr.length; i++){
if(arr[i] !== newArr[newArr.length - 1]){
newArr.push(arr[i]);
}
}
return newArr;
}

输出 newArr 结果:

tip:整体思路就是 先进行排序,将原数组中的第一个元素复制给结果数组,然后检查原数组中的第 i 个元素 与 结果数组中的最后一个元素是否相同。

方法四:使用对象key来去重 (7)

 function unique(arr) {
var newArr = [];
var len = arr.length;
var tmp = {};
for(var i=0; i<len; i++){
if(!tmp[arr[i]]){
tmp[arr[i]] = 1;
newArr.push(arr[i]);
}
}
return newArr;
}

输出 newArr 结果:

tip:整体思路就是 利用了对象(tmp)的 key 不可以重复的特性来进行去重。 但是会出现如下问题需要注意:

          1、无法区分隐式类型转换成字符串后一样的值,比如 1 和 '1' 。

          2、无法处理复杂数据类型,比如对象(因为对象作为key会变成[object Object])。

          3、特殊数据,比如 '__proto__' 会挂掉,因为 tmp 对象的 __proto__ 属性无法被重写。

针对以上问题,解决办法有:

   解决问题一、三:可以为对象的 key 增加一个类型,或者将类型放到对象的value中来解决:(8)

 function unique(arr) {
var newArr = [];
var len = arr.length;
var tmp = {};
var tmpKey;
for(var i=0; i<len; i++){
tmpKey = typeof arr[i] + arr[i]; console.log(tmpKey); if(!tmp[tmpKey]){
tmp[tmpKey] = 1;
newArr.push(arr[i]);
}
}
return newArr;
}

   输出 newArr 结果:

   tip: 代码中第 9 行 console 出来的东西 如图:

          

  解决问题二:可以将对象序列化之后作为key来使用。这里为简单起见,使用JSON.stringify()进行序列化。(9)

 function unique(arr) {
var newArr = [];
var len = arr.length;
var tmp = {};
var tmpKey;
for(var i=0; i<len; i++){
tmpKey = typeof arr[i] + JSON.stringify(arr[i]); console.log(tmpKey) if(!tmp[tmpKey]){
tmp[tmpKey] = 1;
newArr.push(arr[i]);
}
}
return newArr;
}

   输出 newArr 结果:

   tip: 代码中第 9 行 console 出来的东西 如图:

          

     看起来和上面一种方法 console 的没有区别,但是将 测试用例 换成一个 对象  var arr  = [{xiaoming:23,xiaoqing:45},{xiaoming:24,xiaoqing:45}]; 时,可以看到 console 结果如下:

          

以上都是一些比较普遍的解决办法,下面补充一下 es6 中的方法以及对于 null,NaN,undefined,{} 等类型的去重。

一、es6:

方法一: Map (10)

 function unique(arr) {
var newArr = [];
var len = arr.length;
var tmp = new Map();
for(var i=0; i<len; i++){
if(!tmp.get(arr[i])){
tmp.set(arr[i], 1);
newArr.push(arr[i]);
}
}
return newArr;
}

输出 newArr 结果:

tip: Map 是一种新的数据类型,类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。可以把它想象成key类型没有限制的对象。它的存取使用单独的get()、set()接口。

方法二:Set (11)

 function unique(arr){
var set = new Set(arr);
return Array.from(set);
}

输出 newArr 结果:

tip:Set 是一种新的数据结构。它类似于数组,但是成员的值都是唯一的,没有重复的值。Array.from() 方法从类似数组或可迭代对象创建一个新的数组实例。

想要具体了解 Set 和 Map ,查看 http://wiki.jikexueyuan.com/project/es6/set-map.html

方法三:Array.prototype.includes() (12)

 function unique(arr) {
var newArr = [];
arr.forEach(function(item){
if(!newArr.includes(item)){
newArr.push(item);
}
});
return newArr;
}

输出 newArr 结果:

二、NaN 等类型数据的去重:

使用测试用例,对上面所有算法进行验证 (以 黄色数字 为测试顺序)

 var arr = [1,1,'1','1',0,0,'0','0',undefined,undefined,null,null,NaN,NaN,{},{},[],[],/a/,/a/]

 console.log(unique(arr));

得到结果如下:

tips:

That's all ~

学习并感谢:

https://zhuanlan.zhihu.com/p/24753549

http://www.cnblogs.com/fumj/archive/2012/09/09/2677711.html

【 js 算法类】这么全的数组去重,你怕不怕?的更多相关文章

  1. JS常见的几种数组去重方法

    总结一下JS中用到的数组去重的方法  方法一: 该方法利用对象的属性值不能相同: function arrDelLikeElement (array) { const result = []; con ...

  2. JS 数组去重的几种方式

    JS 常见的几种数组去重方法 一.最简单方法(indexOf 方法) 实现思路:新建一个数组,遍历要去重的数组,当值不在新数组的时候(indexOf 为 -1)就加入该新数组中: function u ...

  3. js引用类型数组去重-对象标记法

    前言 Js数组去重已经有很多种实现方式:包括逐个检索对比(使用Array.property.indexOf),先排序后对比,使用hash表,利用ES6中的Set()等.这些数组去重办法中速度最快的是h ...

  4. js数组去重方法分析与总结

    数组去重经常被人拿来说事,虽然在工作中不常用,但他能够很好的考察js基础知识掌握的深度和广度,下面从js的不同阶段总结一下去重的方法. ES3阶段 该阶段主要通过循环遍历数组从而达到去重的目的 多次循 ...

  5. js面试题之数组去重对比

    最近看一些面试题,很多都提到了数组去重,用的最多的不外乎就是下面这个例子 arr.filter(function(value,index,arr){ return arr.indexOf(value, ...

  6. js数组去重的4种方法

    js数组去重,老生长谈,今天对其进行一番归纳,总结出来4种方法 贴入代码前 ,先对浏览器Array对象进行支持indexOf和forEach的polyfill Array.prototype.inde ...

  7. JS 数组去重(数组元素是对象的情况)

    js数组去重有经典的 几种方法 但当数组元素是对象时,就不能简单地比较了,需要以某种方式遍历各值再判断是否已出现. 因为: 1.如果是哈希判断法,对象作哈希表的下标,就会自动转换成字符型类型,从而导致 ...

  8. js中数组去重的几种方法

    js中数组去重的几种方法         1.遍历数组,一一比较,比较到相同的就删除后面的                 function unique(arr){                 ...

  9. js数组去重常用方法

    js数组去重是面试中经常会碰到的问题,无论是前端还是node.js数组常见的有两种形式,一种是数组各元素均为基本数据类型,常见的为数组字符串格式,形如['a','b','c'];一种是数组各元素不定, ...

随机推荐

  1. 网络基础、多线程、ftp任务铺垫

    一.网络基础 学习网络编程,了解一些网络基础的知识是必不可少的,下面学习一些基础的网络知识: 1.我们的电脑里有网卡,网卡里有mac地址: 2.我到某个地方插上网线,路由器或交换机中的DHCP服务为我 ...

  2. 编译lua-5.3.5时出错解决方法

    问题描述: 执行 make linux test 过程出现错误,错误信息如下: “ lua.c:82:31: fatal error: readline/readline.h: No such fil ...

  3. Spring Integration Zip不安全解压(CVE-2018-1261)漏洞复现

    不敢说分析,还是太菜了,多学习. 文章来源: 猎户安全实验室 存在漏洞的源码下载地址:https://github.com/spring-projects/spring-integration-ext ...

  4. VS2013 编辑器

    1. VS -> 本地Git -> Github 1. 右键单击解决方案,选择“将解决方案添加到源代码管理器”,选择Git 2. 切换到团队资源管理器([菜单]视图->团队资源管理器 ...

  5. es 修改拼音分词器源码实现汉字/拼音/简拼混合搜索时同音字不匹配

    [版权声明]:本文章由danvid发布于http://danvid.cnblogs.com/,如需转载或部分使用请注明出处 在业务中经常会用到拼音匹配查询,大家都会用到拼音分词器,但是拼音分词器匹配的 ...

  6. Vue2.5开发去哪儿网App 城市列表开发之 Vuex实现数据共享及高级使用

    一,数据共享 1.  安装: npm install vuex --save 2. 在src目录下 新建state文件夹,新建index.js文件 3. 创建一个 store import Vue f ...

  7. Spring Boot 基础概述与相关约定配置

    今天打算整理一下 Spring Boot 的基础篇,这系列的文章是我业余时间来写的,起源于之前对微服务比较感兴趣,微服务的范畴比较广包括服务治理.负载均衡.断路器.配置中心.API网关等,还需要结合 ...

  8. CDN基本工作过程

    看了一些介绍CDN的文章,感觉这篇是讲的最清楚的. 使用CDN会极大地简化网站的系统维护工作量,网站维护人员只需将网站内容注入CDN的系统,通过CDN部署在各个物理位置的服务器进行全网分发,就可以实现 ...

  9. 工具-CocoaPods安装和使用及卸载

    CocoaPods是iOS最常用的第三方类库管理工具,绝大部分有名的开源类库都支持CocoaPods. 我们在使用gem更新的时候,经常会为速度抓狂,其实gem默认的源是https://rubygem ...

  10. java5新特性-加强for循环

    本文目标是加强for循环和普通for循环的比较.阅读本文大概3-5分钟 刚开始学习编程语言的时候接触了三种循环方式 1. for 常用 2. while 较常用 3 do ... while 不常用 ...