JS实用功能-9、面试中常遇见的数组去重
JS数组去重是面试中并不少见的问题,听起来很简单,当你兴高采烈地回答了你的方法之后,你以为这道题就结束了吗?No,一般来说,面试官会继续问你“除了你刚刚说的方法,还有其他更好的方法吗?”,这时的你就需要了解多几种JS数组去重的方法了。
下面我们先来看看常见的去重方法先吧。
一、双重for循环
拿前一个数据和后面的数据做对比,与后面相同的就删除。
//方法1 const unique = arr => { if(!(arr instanceof Array) || arr.length == 0){ console.log('数组数据异常'); return; } 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; }
测试数据:
let arr = [1,1,false,false,true,true,null,null,undefined,undefined,NaN,NaN,{},{},'a','a'];
测试结果:
在结果中可以看出,部分相同的数据都已经被去掉了,但是true、NaN、{}这三个是没有去除的。应该是“==”判断的问题。
可以来看看NaN的情况:
两个NaN对比,居然是个false,难怪没有去重成功。其他应该也是相对如此的,那么这种去重方法还是存在不足的。
二、单个for循环和indexOf
遍历原数组,将每个元素插入到新数组中。插入前先判断新数组中是否存在改元素。利用数组的indexOf方法来查重,有就返回元素在数组中的下标,不存在就返回-1.
const unique = arr => {
..... let arr1 = [];// 新建一个数组来存放arr中的元素 for(let i = 0; i < arr.length; i++){ if(arr1.indexOf(arr[i]) == -1){ arr1.push(arr[i]); } } return arr1; }
测试数据:
let arr = [1,1,false,false,true,true,null,null,undefined,undefined,NaN,NaN,{},{},'a','a'];
输出结果:
看来这个对true去重有作用了呀,但是NaN、{}还是不起作用。
三、单个for循环和includes
这个跟第二个差不多,不同的是重复判断用的是数组的includes方法,它返回是Boolean类型,如果包含某个元素就返回true,反正false。
const unique = arr => { ..... let arr1 = [];// 新建一个数组来存放arr中的元素 for(let i = 0; i < arr.length; i++){ if(!arr1.includes(arr[i])){ arr1.push(arr[i]); } } return arr1; }
测试数据:
let arr = [1,1,false,false,true,true,null,null,undefined,undefined,NaN,NaN,{},{},'a','a'];
输出结果:
这次比前两次好了很多,能判断NaN了。
四、单个for循环和sort
先用sort方法对数组进行排序,然后对比相邻两个元素是否相等,做去重处理。
const unique = arr => {
..... arr = arr.sort(); let arr1 = [arr[0]]; for(let i = 1;i < arr.length;i++){ if(arr[i] !== arr[i-1]){ arr1.push(arr[i]); } } return arr1; }
测试数据:
let arr = [1,1,false,false,true,true,null,null,undefined,undefined,NaN,NaN,{},{},'a','a'];
测试结果:
效果还是很好的嘛。
五、ES6的Set集合
Set集合作为ES6新加入的数据结构,存储类似于数组,但是里面的元素是不能重复的。我们可以先将数组转成Set集合,去重之后,再转为数组输出。
const unique = arr => {
..... return Array.from(new Set(arr)) }
Array.from()方法就是将一个类数组对象或者可遍历对象转换成一个真正的数组,不过它也是ES6的新特性。
测试数据:
let arr = [1,1,false,false,true,true,null,null,undefined,undefined,NaN,NaN,{},{},'a','a'];
测试结果:
看来效果还是很不错的啊,除了 {} 不能去重外,其他都完成了。
六、数组的filter函数
filter()会创建一个新数组,循环对数组中的元素调用callback函数, 如果返回true 保留,如果返回false 过滤掉, 返回新数组,老数组不变。
const unique = arr => { return arr.filter((item,index) => { return arr.indexOf(item) === index; }); }
测数据:
let arr = [1,1,false,false,true,true,null,null,undefined,undefined,NaN,NaN,{},{},'a','a'];
测试结果:
这个方法也是除了 {} 无法去重外,其他都可以成功了。
七、ES6的Map对象
Map作为ES6的一种新型数据结构,类似json,用键值对方式存储数据。Map中有has()方法,返回一个Boolean类型,来表明Map中是否存在指定元素。
const unique = arr => { ..... let map = new Map(); let arr1 = [] for (let i = 0; i < arr.length; i++) { if (map.has(arr[i])) { // 判断是否存在该key值 map.set(arr[i], true); } else { map.set(arr[i], false); arr1.push(arr[i]); } } return arr1; }
测试数据:
let arr = [1,1,false,false,true,true,null,null,undefined,undefined,NaN,NaN,{},{},'a','a'];
测试结果:
也是除了{}去不了重之外,其他都正常。
八、递归
这种方法其实跟第一种方法差不多,通过循环判断前一个元素和后面元素是否相同来查重。不过要求掌握递归算法的。
const unique = arr => { let arr1 = arr; let len = arr1.length; function loop(index){ if(index >= 1){ if(arr1[index] === arr1[index-1] ){ arr1.splice(index,1); } loop(index - 1); // 递归loop,然后数组去重 } } loop(len-1); return arr1; }
测试数据:
let arr = [1,1,false,false,true,true,null,null,undefined,undefined,NaN,NaN,{},{},'a','a'];
测试结果:
处理NaN和{}无法去重外,其他都没问题。
上面的方法都能解决日常开发中的大部分去重问题,但都不能解决 {} 去重问题,难道就真的没办法了吗?
对象是永不相等的,在用 === 号的情况下,因为它们属于引用类型,在三等符号的情况下判断是内存地址了,当且仅当它们引用同一个基对象时,它们才相等。
九、Map和Set对JSON数组去重
其实可以将对象转换成字符串,然后让字符串对比,就可以做到去重的效果。
const unique = arr => { const map = new Map() return arr.filter( item => !map.has(JSON.stringify(item)) && map.set(JSON.stringify(item), 1)); }
测试数据1:
let json = [{},{}];
测试结果1:
测试数据2:
let json2 = [{a: 1, b: 2}, {a: 1, b: 2}];
测试结果2:
通过上面的方法也就很好的解决了 对象 相等的问题,其实知道原理之后,用for循环也是可以解决的,但是,最近在学ES6,顺便装一下13。
上面就是这篇的全部内容了。