【跟着大佬学JavaScript】之数组去重(结果对比)
前言
数组去重在面试和工作中都是比较容易见到的问题。
这篇文章主要是来测试多个方法,对下面这个数组的去重结果进行分析讨论。如果有不对的地方,还请大家指出。
const arr = [ 1, 1, "1", "1", 0, 0, "0", "0", true, false, "true", "false", "a", "A", undefined, undefined, "undefined", null, null, 'null', NaN, NaN, +0, -0, new String("1"), new String("1"), Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], [] ];
特殊类型
console.log(1 == "1"); // true
console.log(1 === "1"); // false
console.log(0 == "0"); // true
console.log(0 === "0"); // false
console.log(0 == +0); // true
console.log(0 === +0); // true
console.log(0 == -0); // true
console.log(0 === -0); // true
console.log(+0 == -0); // true
console.log(+0 === -0); // true
console.log(0 == false); // true
console.log(0 === false); // false
console.log(0 == undefined); // false
console.log(0 === undefined); // false
console.log(0 == null); // false
console.log(0 === null); // false
console.log(1 == true); // true
console.log(1 === true); // false
console.log(undefined == null); // true
console.log(undefined === null); // false
console.log(NaN == NaN); // false
console.log(NaN === NaN); // false
console.log(new String("1") == new String("1")); // false
console.log(new String("1") === new String("1")); // false
Object.prototype.toString.call(new String('1')) // '[object String]'
console.log(/a/ == /a/); // false
console.log(/a/ === /a/); // false
Object.prototype.toString.call(/a/); //'[object RegExp]'
console.log(Symbol(1) == Symbol(1)); // false
console.log(Symbol(1) === Symbol(1)); // false
console.log({} == {}); // false
console.log({} === {}); // false
console.log([] == []); // false
console.log([] === []); // false
接下来,我们看看下面多个去重方法,对以上特殊类型的去重效果。
代码一(暴力解法)
// 暴力解法一
function unique(array) {
if (!Array.isArray(array)) {
console.log("type error!");
return;
}
const res = [array[0]];
let arrLen = array.length;
let resLen = res.length;
for (let i = 0; i < arrLen; i++) {
let flag = true;
for (let j = 0; j < resLen; j++) {
if (array[i] === res[j]) {
flag = false;
break;
}
}
if (flag) {
res.push(array[i]);
resLen = res.length;
}
}
return res;
}
// [1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []]
输出:
[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []]
输出结果说明:
- 去重
+0
、-0
、0
NaN
不去重- 对象
new String("1")
、/a/
、{}
不去重 - 数组
[]
不去重 Symbol(1)
不去重
暴力解法,简单易理解,兼容性好。去重结果如上所示。
代码二(ES6)
// ES6 Array.from + Set 方法一
function unique(array) {
if (!Array.isArray(array)) {
console.log('type error!')
return
}
return Array.from(new Set(array))
}
// ES6 点运算 + Set 方法二
function unique1(array) {
if (!Array.isArray(array)) {
console.log('type error!')
return
}
return [...new Set(arr)]
}
// ES6 箭头函数 + 点运算 + Set 方法三
const unique2 = (array) => {
if (!Array.isArray(array)) {
console.log('type error!')
return
}
return [...new Set(arr)]
}
// ES6 Map + ES5 filter 方法四
function unique3(array) {
if (!Array.isArray(array)) {
console.log('type error!')
return
}
const seen = new Map()
return array.filter((a) => !seen.has(a) && seen.set(a, 1))
}
输出:
[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []]
输出结果说明:
- 去重
+0
、-0
、0
- 去重
NaN
- 对象
new String("1")
、/a/
、{}
不去重 - 数组
[]
不去重 Symbol(1)
不去重
代码三(indexOf + forEach)
利用indexOf检测元素在新数组是否存在
// indexOf + forEach 利用indexOf检测元素在新数组是否存在
function unique(array) {
if (!Array.isArray(array)) {
console.log('type error!')
return
}
const newArr = [];
array.forEach((el) => {
if (newArr.indexOf(el) === -1) {
newArr.push(el);
}
});
return newArr;
}
输出:
[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []]
输出结果说明:
- 去重
+0
、-0
、0
NaN
不去重- 对象
new String("1")
、/a/
、{}
不去重 - 数组
[]
不去重 Symbol(1)
不去重
代码四(indexOf + filter)
利用indexOf检测元素在数组中第一次出现的位置是否和元素现在的位置相等
// indexOf + forEach 利用indexOf检测元素在新数组是否存在
function unique(array) {
if (!Array.isArray(array)) {
console.log('type error!')
return
}
return array.filter((item, index) => {
return array.indexOf(item) === index;
});
}
console.log([NaN].indexOf(NaN)); // -1
输出:
[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []]
输出结果说明:
- 去重
+0
、-0
、0
- 两个
NaN
都会被删除 - 对象
new String("1")
、/a/
、{}
不去重 - 数组
[]
不去重 Symbol(1)
不去重
重点:
console.log([NaN].indexOf(NaN)); // -1
代码五(sort排序,不支持Symbol)
sort()方法主要是用于对数组进行排序,默认情况下该方法是将数组元素转换成字符串,然后按照ASC码进行排序
// sort()方法不支持Symbol,Symbol不支持转换成字符串
function unique(array) {
if (!Array.isArray(array)) {
console.log("type error!");
return;
}
const sortArr = array.sort();
const newArr = [];
sortArr.forEach((el, i) => {
if (sortArr[i] !== sortArr[i - 1]) {
newArr.push(el);
}
});
return newArr;
}
输出:
[[], [], /a/, /a/, 0, "0", 0, 1, "1", String {'1'}, String {'1'}, "A", NaN, NaN, {}, {}, "a", false, "false", null, "null", true, "true", "undefined", undefined]
输出结果说明:
+0
、-0
、0
、"0"
位置不同会导致去重不了NaN
不去重- 对象
new String("1")
、/a/
、{}
不去重 - 数组
[]
不去重 - sort()方法不支持处理含有
Symbol
的数组
代码六(includes)
利用includes()方法检查新数组是否包含原数组的每一项
// 利用includes()方法检查新数组是否包含原数组的每一项
function unique(array) {
if (!Array.isArray(array)) {
console.log("type error!");
return;
}
const newArr = [];
array.forEach((el) => {
newArr.includes(el) ? newArr : newArr.push(el);
});
return newArr;
}
输出:
[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []]
输出结果说明:
- 去重
+0
、-0
、0
- 去重
NaN
- 对象
new String("1")
、/a/
、{}
不去重 - 数组
[]
不去重 Symbol
不去重
代码七(includes+reduce)
利用includes()方法检查新数组是否包含原数组的每一项
// 利用includes()方法检查新数组是否包含原数组的每一项
function unique(array) {
if (!Array.isArray(array)) {
console.log("type error!");
return;
}
return array.reduce((pre, cur) => {
!pre.includes(cur) && pre.push(cur);
return pre;
}, []);
}
输出:
[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []]
输出结果说明:
- 去重
+0
、-0
、0
- 去重
NaN
- 对象
new String("1")
、/a/
、{}
不去重 - 数组
[]
不去重 Symbol
不去重
代码八(对象key)
利用了对象的key不可以重复的特性来进行去重
// 利用了对象的key不可以重复的特性来进行去重
function unique(array) {
if (!Array.isArray(array)) {
console.log("type error!");
return;
}
const obj = {};
const newArr = [];
array.forEach((val) => {
if (!obj[typeof val + JSON.stringify(val)]) {
// 将对象序列化之后作为key来使用
obj[typeof val + JSON.stringify(val)] = 1;
newArr.push(val);
}
});
return newArr;
}
输出:
[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, String {'1'}, Symbol(1), {}, []]
输出结果说明:
- 去重
+0
、-0
、0
- 去重
NaN
- 去重对象
new String("1")
、{}
;两个/a/
全部被删除了 - 去重数组
[]
- 去重
Symbol
将不该去重的Symbol
去重了;将两个/a/
全部删除了
总结
方法 | 结果 | 说明 |
---|---|---|
for循环暴力解法 | [1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []] |
1.去重+0、-0、0; 2.NaN不去重;3.对象new String("1")、/a/、{}不去重;4.数组[]不去重;5.Symbol(1)不去重; |
ES6解法 | [1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], [] |
1.去重+0、-0、0; 2.去重NaN;3.对象new String("1")、/a/、{}不去重;4.数组[]不去重;5.Symbol(1)不去重; |
indexOf + forEach | [1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []] |
1.去重+0、-0、0; 2.NaN不去重;3.对象new String("1")、/a/、{}不去重;4.数组[]不去重;5.Symbol(1)不去重; |
indexOf + filter | [1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []] |
1.去重+0、-0、0; 2.两个NaN都会被删除;3.对象new String("1")、/a/、{}不去重;4.数组[]不去重;5.Symbol(1)不去重; |
sort排序,不支持Symbol | [[], [], /a/, /a/, 0, "0", 0, 1, "1", String {'1'}, String {'1'}, "A", NaN, NaN, {}, {}, "a", false, "false", null, "null", true, "true", "undefined", undefined] |
1.+0、-0、0、"0"位置不同会导致去重不了 2.NaN不去重;3.对象new String("1")、/a/、{}不去重;4.数组[]不去重;5.sort()方法不支持处理含有Symbol的数组; |
includes | [1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []] |
1.去重+0、-0、0; 2.去重NaN;3.对象new String("1")、/a/、{}不去重;4.数组[]不去重;5.Symbol(1)不去重; |
includes+reduce | [1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []] |
1.去重+0、-0、0; 2.去重NaN;3.对象new String("1")、/a/、{}不去重;4.数组[]不去重;5.Symbol(1)不去重; |
对象key | [1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, String {'1'}, Symbol(1), {}, []] |
1.去重+0、-0、0; 2.去重NaN;3.去重对象new String("1")、{};两个/a/全部被删除了;4.去重数组[];5.去重Symbol |
上面只是简单结果的去重总结,具体的去重选择还需要根据我们业务场景来选择去重方法。
演示地址
可以去Github仓库查看演示代码
跟着大佬学系列
主要是日常对每个进阶知识点的摸透,跟着大佬一起去深入了解JavaScript的语言艺术。
后续会一直更新,希望各位看官不要吝啬手中的赞。
️ 感谢各位的支持!!!
️ 如果有错误或者不严谨的地方,请务必给予指正,十分感谢!!!
️ 喜欢或者有所启发,欢迎 star!!!
参考
原文地址
【跟着大佬学JavaScript】之数组去重(结果对比)的更多相关文章
- 【跟着大佬学JavaScript】之节流
前言 js的典型的场景 监听页面的scroll事件 拖拽事件 监听鼠标的 mousemove 事件 ... 这些事件会频繁触发会影响性能,如果使用节流,降低频次,保留了用户体验,又提升了执行速度,节省 ...
- 【跟着大佬学JavaScript】之lodash防抖节流合并
前言 前面已经对防抖和节流有了介绍,这篇主要看lodash是如何将防抖和节流合并成一个函数的. 初衷是深入lodash,学习它内部的好代码并应用,同时也加深节流防抖的理解.这里会先从防抖开始一步步往后 ...
- JavaScript 实现数组去重
JavaScript 实现数组去重 演示Demo 数组去重 // 方法一 function unique1(a) { var res = []; for (var i = 0, len = a.len ...
- JavaScript中数组去重的几种方法
JavaScript中数组去重的几种方法 正常情况下,数据去重的工作一般都是由后端同事来完成的,但是前端也要掌握好处理数据的能力,万一去重的工作交给我们大前端处理,我们也不能怂呀.现在我总结了一些去重 ...
- JavaScript实现数组去重方法
一.利用ES6 Set去重(ES6中最常用) function unique (arr) { return Array.from(new Set(arr)) } var arr = [1,1,'tru ...
- JavaScript之数组去重
前言:昨天看到了别人发的帖子,谈到了面试题中经常出现的数组去重的问题.作为一个热爱学习.喜欢听老师话的好孩纸,耳边忽然想起来高中老师的谆谆教导:不要拿到题就先看答案,要先自己思考解答,然后再对照答案检 ...
- 使用JavaScript进行数组去重——一种高效的算法
最近比较忙,没时间更新博客,等忙完这阵子会整理一篇使用AngularJS构建一个中型的单页面应用(SPA)的文章,尽情期待!先占个坑. 数组去重的算法有很多种,以下是一种. 思路如下: 定义一个空的对 ...
- JavaScript 高性能数组去重
中午和同事吃饭,席间讨论到数组去重这一问题 我立刻就分享了我常用的一个去重方法,随即被老大指出这个方法效率不高 回家后我自己测试了一下,发现那个方法确实很慢 于是就有了这一次的高性能数组去重研究 一. ...
- Javascript作业—数组去重(要求:原型链上添加函数)
数组去重(要求:原型链上添加函数) <script> //数组去重,要求:在原型链上添加函数 //存储不重复的--仅循环一次 if(!Array.prototype.unique1){ A ...
随机推荐
- 《Mybatis 手撸专栏》第7章:SQL执行器的定义和实现
作者:小傅哥 博客:https://bugstack.cn - <手写Mybatis系列> 一.前言 为什么,要读框架源码? 因为手里的业务工程代码太拉胯了!通常作为业务研发,所开发出来的 ...
- 简述 private、protected、 public、 internal修饰符的访问权限
1.private: 私有的,只能在此类中访问 2.protected: 受保护的,只能在此类及其继承类中访问 3.public: 公开的,没有访问限制 4:internal: 内部的,只能在当前程序 ...
- 改善java程序
1.用偶判断,不用奇判断.因为负数会出错. // 不使用 String str = i + "->" + (i%2 == 1? "奇数": "偶 ...
- VMware服务关闭后一定要重启
重要的事情说三遍:服务暂时关闭记得重启,服务暂时关闭记得重启,服务暂时关闭记得重启!!! VMware服务由于安装补丁的需要我暂时把服务关闭了,于是我遇到了尴尬的一幕,于是乎发现上不了网了,于是各种操 ...
- 交互式 .Net 容器版
背景介绍 在之前的文章 - 交互式 .Net 中已经介绍了什么是交互式 .Net,文中是通过 Visual Studio Code 插件的方式实现交互式 .Net 的.现在,我们将使用容器的方式实现交 ...
- FinClip 前端之 VUE 核心原理总结
小程序框架有很多,都是支持前端JavaScript语言的,也是支持 vue.js 框架的.FinClip 小程序是兼容各家平台的.所以在学习了框架使用之后的进阶就要熟悉框架的底层原理. 1.数据响应式 ...
- 【算法】选择排序(Selection Sort)(二)
选择排序(Selection Sort) 选择排序(Selection-sort)是一种简单直观的排序算法.它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余 ...
- python使用vosk进行中文语音识别
操作系统:Windows10 Python版本:3.9.2 vosk是一个离线开源语音识别工具,它可以识别16种语言,包括中文. 这里记录下使用vosk进行中文识别的过程,以便后续查阅. vosk地址 ...
- 103_Power Pivot 透视表中空白标签处理及百分比
焦棚子的文章目录 请点击下载附件 1.案例来源于不断变化的需求 事实表:销售表 维度表:城市表 销售表和城市建立多对一的关系 如图1: 图1 2.插入透视表 如图2: 图2 3.问题 1.销售表中,城 ...
- axios知识点总结
是什么? 前端最流行的 ajax 请求库 基于Promise的HTTP客服端,可以在浏览器和服务器两个环境去运行. 特点 基于 xhr + promise 的异步 ajax 请求库 浏览器端/node ...