前端面试手写代码——JS数组去重
1 测试用例
// 测试用例
const a = {};
const b = { c: 1 };
const array = [
1, 1, "1", "1",
{}, {}, { c: 1 }, { c: 1},
a, a, b, b,
[], [], [1], [1],
undefined, undefined,
null, null,
NaN, NaN,
];
2 JS 数组去重4大类型
2.1 元素比较型
此类型通过数组元素之间进行比较来去重
2.1.1 双层 for 循环逐一比较(es5常用)
使用双层for 循环逐一比较数组元素,用splice方法去除重复的元素
// 双层for循环
function uniq1(arr) {
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (arr[i] === arr[j]) {
arr.splice(j, 1)
j--
}
}
}
return arr
}
// 去重结果
// [1,'1',{},{},{c:1},{c:1},{},{c:1},[],[],[1],[1],undefined,null,NaN,NaN]
通过对比去重前后结果,重复的NaN没有去掉,因为NaN === NaN为false
2.1.2 排序相邻比较
使用sort()方法对数组元素进行排序,然后比较相邻元素,用splice方法去除重复的元素。
function uni2(arr) {
arr.sort();
for (let i = 0; i < arr.length - 1; i++) {
arr[i] === arr[i + 1] && arr.splice(i + 1, 1) && i--;
}
return arr;
}
也可以创建新数组,将不重复的元素放入新数组中
function uniq3(arr) {
arr = arr.sort()
const newArr = [arr[0]]
for (let i = 1; i < arr.length; i++) {
if (arr[i] !== arr[i - 1]) {
newArr.push(arr[i])
}
}
return newArr
}
// 去重结果
// [[],[],1,'1',[1],[1],NaN,NaN,{},{},{c:1},{c:1},{},{c:1},null,undefined]
- 重复的
NaN没有去掉,因为NaN === NaN为false sort默认排序顺序是将元素转换为字符串,对象转换为字符串都是[object Object],所以sort方法不能对数组中的对象进行排序,也就有可能无法去除重复的对象,除非重复的对象本就相邻
2.2 查找元素位置型
此类型通过查找元素第一次出现的位置来去重
2.2.1 indexOf
通过indexOf查找当前元素第一次出现的位置是否为当前位置,若是,则放入新数组
function uniq4(arr) {
let res = []
for (let i = 0; i < arr.length; i++) {
if (arr.indexOf(arr[i]) === i) {
res.push(arr[i])
}
}
return res
}
// 去重结果
// [1,'1',{},{},{c:1},{c:1},{},{c:1},[],[],[1],[1],undefined,null]
同样,因为NaN === NaN为false,所以用indexOf查找NaN结果总是-1,从而在新数组中不会有NaN
2.2.2 findIndex
通过findIndex查找当前元素第一次出现的位置是否为当前位置,若是,则放入新数组
function uniq5(arr) {
let res = []
for (let i = 0; i < arr.length; i++) {
if (arr.findIndex(item => item === arr[i]) === i) {
res.push(arr[i])
}
}
return res
}
// 去重结果
// [1,'1',{},{},{c:1},{c:1},{},{c:1},[],[],[1],[1],undefined,null]
同样,因为NaN === NaN为false,所以用findIndex查找NaN结果总是-1,从而在新数组中不会有NaN
2.3 元素是否存在型
此类型通过判断在新数组中是否存在当前元素来去重
2.3.1 includes
includes方法用来判断一个数组是否包含一个指定的值
function uniq6(arr) {
let res = []
for (let i = 0; i < arr.length; i++) {
if (!res.includes(arr[i])) {
res.push(arr[i])
}
}
return res
}
// 去重结果
// [1,'1',{},{},{c:1},{c:1},{},{c:1},[],[],[1],[1],undefined,null,NaN]
includes使用零值相等算法来确定是否找到给定的元素,所以可以判断NaN是否在新数组中存在
2.3.2 some
some方法用来测试数组中是否至少有1个元素通过了被提供的函数测试
function uniq7(arr) {
let res = []
for (let i = 0; i < arr.length; i++) {
if (!res.some(item => item === arr[i])) {
res.push(arr[i])
}
}
return res
}
// 去重结果
// [1,'1',{},{},{c:1},{c:1},{},{c:1},[],[],[1],[1],undefined,null,NaN,NaN]
同样,这里仍旧使用了===来比较元素,因为NaN === NaN为false,所以新数组中会有多个NaN
2.4 依托数据结构特性
此类型通过ES6提供的数据结构Map、Set本身不可重复特性来去重
2.4.1 Map
ES6提供的Map结构可以用各种类型的值(包括对象)当作键,且键是唯一的
function uniq8(arr) {
const map = new Map()
for (let i = 0; i < arr.length; i++) {
!map.has(arr[i]) && map.set(arr[i], true)
}
return [...map.keys()]
}
// 去重结果
// [1,'1',{},{},{c:1},{c:1},{},{c:1},[],[],[1],[1],undefined,null,NaN]
map.has方法对NaN也有效
2.4.2 Set(ES6 最常用)
Set结构的成员的值都是唯一的,没有重复的值。
function uniq9(arr) {
return [...new Set(arr)]
}
// 去重结果
// [1,'1',{},{},{c:1},{c:1},{},{c:1},[],[],[1],[1],undefined,null,NaN]
3 补充
上面所说的方法可以使用不同的
Api进行改动,比如使用splice方法去除数组元素的地方,我们可以通过filter方法来过滤数组得到新数组;再比如
includes的方法中不用for循环遍历数组,通过reduce方法来代替等等。总之,方法有很多,但是万变不离其宗
有些去重方法对
NaN无效,因为NaN === NaN为false,如果有需求,可以使用Object.is(NaN, NaN)为true来进行修改实际应用中,最常用的方法就是使用
Set,也可以使用第三方库lodash来处理
前端面试手写代码——JS数组去重的更多相关文章
- 前端面试手写代码——JS函数柯里化
目录 1 什么是函数柯里化 2 柯里化的作用和特点 2.1 参数复用 2.2 提前返回 2.3 延迟执行 3 封装通用柯里化工具函数 4 总结和补充 1 什么是函数柯里化 在计算机科学中,柯里化(Cu ...
- 前端面试手写代码——call、apply、bind
1 call.apply.bind 用法及对比 1.1 Function.prototype 三者都是Function原型上的方法,所有函数都能调用它们 Function.prototype.call ...
- 前端面试手写代码——模拟实现new运算符
目录 1 new 运算符简介 2 new 究竟干了什么事 3 模拟实现 new 运算符 4 补充 预备知识: 了解原型和原型链 了解this绑定 1 new 运算符简介 MDN文档:new 运算符创建 ...
- js面试-手写代码实现new操作符的功能
我们要搞清楚new操作符到底做了一些什么事情? 1.创建一个新的对象 2.将构造函数的作用域赋给新对象(因此this指向了这个新对象) 3.执行构造函数中的代码(为这个新对象添加属性) 4.返回新对象 ...
- zen-coding for notepad++,前端最佳手写代码编辑器
zen-Coding是一款快速编写HTML,CSS(或其他格式化语言)代码的编辑器插件,这个插件可以用缩写方式完成大量重复的编码工作,是web前端从业者的利器. zen-Coding插件支持多种编辑器 ...
- Java面试手写代码题
1.栈实现 2.Iterator实现 3.单例 4.多线和控制(暂停,恢复,停止) 5.生产者消费者
- 2019前端面试系列——JS高频手写代码题
实现 new 方法 /* * 1.创建一个空对象 * 2.链接到原型 * 3.绑定this值 * 4.返回新对象 */ // 第一种实现 function createNew() { let obj ...
- js数组去重解决方案
js数组去重是前端面试中经常被问的题目,考察了面试者对js的掌握,解决问题的思路,以及是否具有专研精神.曾经一位前端界大神告诉我,解决问题的方式有很多种,解决问题时多问问自己还有没有其他的方法,探求最 ...
- 手写Koa.js源码
用Node.js写一个web服务器,我前面已经写过两篇文章了: 第一篇是不使用任何框架也能搭建一个web服务器,主要是熟悉Node.js原生API的使用:使用Node.js原生API写一个web服务器 ...
随机推荐
- 01-mysql必知必会
概述 主键:唯一区分表中每个行(不可重复,不允许null mysql:基于客户-服务器的数据库系统 使用mysql mysql是部署在主机上的,可以通过ssh建立mysql连接 # 显示数据库 sho ...
- mysql更新数据时:当想mysql某插入有某字段设置了unique且和之前相同时,会报错,并停止运行
这个在mysql5.7会报错: 如openid设为unique: 1062 - Duplicate entry 'oTfYq6PKne00IrcTqphmKqKnsahM' for key 'qx_w ...
- Shell系列(37)- while和until循环
while循环 只要条件判断式成立则进行循环,并执行循环程序:一旦循环条件不成立,则终止循环 格式 while [ 条件判断式 ] do 程序 done 例子 需求:计算工具,1+2+--100的和 ...
- 常用的jquery 中一些js
目录: 1.验证用户登录信息 2. 获取下拉框所选中的元素 3. 动态获取 id 和对应文本框的值 4. table 中 tr 的隐藏 5 . 更换图片 6. ajax 进行提交 7. 判断 ...
- [转载]linux上用PHP读取WORD文档
在linux上用PHP读取WORD文档,其实是使用了 antiword程序把word文档转化为txt文档. 再使用php执行系统命令调用而已. 具体操作如下: 1.安装antiword 官方站:htt ...
- P3507-[POI2010]GRA-The Minima Game【dp,博弈论】
正题 题目链接:https://www.luogu.com.cn/problem/P3507 题目大意 \(n\)个数,没人轮流取若干个并获得取走的数中最小数的权值,两人的目标都是自己的权值\(-\) ...
- spring 创建Bean最全实现方法
创建bean方式,spring创建bean的方式包含:自动注入方式和人工注入方式.分别为:1)xml 配置化方式 2)@bean注解注入方式3)@Component方式 4)接口注入方式 5)imp ...
- 题解 SP6779 【GSS7 - Can you answer these queries VII】
题目传送门 题目大意 给出一个\(n\)个点的树,每个点有权值.有\(m\)次操作,每次要么查询一条链上的最大子段和,要么把一条链的权值都修改为一个常数. \(n,m\le 10^5\) 思路 如果是 ...
- uoj21 缩进优化(整除分块,乱搞)
题目大意: 给定一个长度为\(n\)的序列 让你找一个\(x\),使得\(ans\)尽可能小 其中$$ans=\sum_{i=1}^{n}\lfloor\frac{a_i}{x}\rfloor + \ ...
- QFNU-ACM 2021.10.09 Rating补题
A - A CodeForces - 478A 注意点: 和为0时要特判一下. 代码: #include<bits/stdc++.h> using namespace std; int m ...