前言
数组去重是面试时候常考的,我们日常工作中,也经常会遇到, 接下来就归纳总结几种数组去重的方案, 在我们开发和面试的时候可以得心应手,
分类
在实现数组去重之前我们我们简单进行一下分类, 数组去重,我们一般 分为单个数组去重 和多个数组交叉去重, 接下来我们就从单个数组开始
一、简单的数组去重
简单数组去重经常是普通数组进行去重, 我们常用的是利用new Set去重、利用indexOf、数组方法 some、 filter 、reduce 等
1、new Set
这种方案很简单, 就是将数组转化成Set结构, 利用Set结构的唯一性去重, 然后再转化为数组
const arr = [1,2,3,1,2,2] new Set(arr) set 结构转换成 数组 有两种方式 [...new Set(arr)]和 Array.from(new Set(arr)) // [1, 2, 3]
2、使用 遍历(map、for循环、forEach) + indexOf
const arr = [1,2,3,1,2,2] let arr2 = [] for(let i=0;i<arr.length;i++){ if(arr2.indexOf(arr[i]) === -1){ arr2.push(arr[i]) } } //=> arr2 [1, 2, 3]
3、使用 reduce、reduceRight 去重
上面的方法其实是经典的面相过程的写法,我们为了达到结果,引入了新的变量arr2 , 如果是面向对象的写法,又不引入新的变量,我们经常使用 reduce、reduceRight
const arr = [1,2,3,1,2,2] arr.reduce((result, cur, index, array)=>{ if(result.indexOf(cur) === -1){ result.push(cur) } return result },[])
4、利用对象 key的唯一性 去重
再考虑去重的时候,经常也会使用 对象的key唯一性这个特点进行去重, 先写一个面向过程的写法, 引入一个变量 obj
const obj = {} const result = [] const arr = [1,2,3,1,2,2] arr.map(el=>{ if(!obj[el]){ result.push(el) obj[el] = el } }) console.log(result) //=> [1, 2, 3]
同理 也可也通过面向对象方式 用reduce 解决
const arr = [1,2,3,1,2,2] const obj = {} arr.reduce((result, cur, index,array)=>{ if(!obj[cur]){ result.push(cur) obj[cur] = cur } return result },[]) //=> [1, 2, 3]
5、filter 去重
const arr = [1,2,3,1,2,2] arr.filter((el,index)=> !arr.slice(0,index).some(t=> t === el)) 或 arr.filter((el,index)=> arr.indexOf(el) //=> [1, 2, 3]
二、复杂的JSON数组去重
复杂数组去重 , 一般是 JSON数组去重, 根据某个对象的key相同去重, 基本上大体也是利用上面简单数组去重的原理。
下面以这个举例, 我们按照相同id去重
const arr = [{id:1, name: 'liming'},{id:2, name:'xiaohong'}, {id:1, name: 'liming2'}]
1、使用 遍历(map、for循环、forEach) + indexOf
let arr = [{id:1, name: 'liming'},{id:2, name:'xiaohong'}, {id:1, name: 'liming2'}] let arr2 = [] let result = [] for(let i=0;i<arr.length;i++){ if(arr2.indexOf(arr[i].id) === -1){ result.push(arr[i]) arr2.push(arr[i].id) } } // result => [{id: 1, name: 'liming'},{id: 2, name:'xiaohong}] // arr2 => [1,2]
这里也是通过 arr2 的引入,来存取id每个对象中id的值。 判断是否已存在这个id ,在判断是否讲 item 放入 result中
2、使用 reduce、reduceRight 去重
let arr = [{id:1, name: 'liming'},{id:2, name:'xiaohong'}, {id:1, name: 'liming2'}] arr.reduce((result, cur, index, array)=>{ let r = array.slice(0,index).filter(el=> el.id === cur.id) if(!r.length){ result.push(cur) } return result },[]) // result => [{id: 1, name: 'liming'},{id: 2, name:'xiaohong}] // arr2 => [1,2]
3、利用对象 key的唯一性 去重
let arr = [{id:1, name: 'liming'},{id:2, name:'xiaohong'}, {id:1, name: 'liming2'}] let obj = {} let result = [] arr.map((cur,index)=>{ f(!obj[cur.id]){ result.push(cur) obj[cur.id] = true } }) // result => [{id: 1, name: 'liming'},{id: 2, name:'xiaohong}]
4、利用 map + filter
let arr = [{id:1, name: 'liming'},{id:2, name:'xiaohong'}, {id:1, name: 'liming2'}] let result = [] arr.map((cur, index)=>{ let r = arr.slice(0,index).filter(el=> el.id === cur.id) if(!r.length){ result.push(cur) } return result }) // result => [{id: 1, name: 'liming'},{id: 2, name:'xiaohong}]
三、其他数组去重的需求
1、复杂去重 加 合并重复项的某些值
如下面objArray中,根据id过滤,并且处理,将name和number的值汇总成数组
objArray = [ { id: 1, name: "A", number: 1 }, { id: 2, name: "B", number: 2 }, { id: 1, name: "B", number: 3 }, { id: 1, name: "C", number: 4 }, { id: 1, name: "D", number: 5 }, ]; let newArr = objArray.reduceRight((cur, item, index, array) => { let curArr = cur.filter((c) => c.id === item.id); if (curArr.length > 0) { let nameObj = cur.find((oo) => oo.id === item.id); nameObj.name = Array.isArray(nameObj.name) ? [...nameObj.name, item.name] : [nameObj.name, item.name]; nameObj.number = Array.isArray(nameObj.number) ? [...nameObj.number, item.number] : [nameObj.number, item.number]; } else { cur.push(item); } return cur; }, []); console.log(newArr, "newArr"); //=> [{"id":1,"name":["D","C","B","A"],"number":[5,4,3,1]},{"id":2,"name":"B","number":2}]
2、 两个数组的去重
下面案例将arr2 根据arr1 的相同id 去重 , 常用 filter + some 结合去重
let arr1 = [{id:1, name:'liming'},{id:2, name:'xiaohong'}] let arr2 = [{id:3, name:'zhangfei'},{id:2, name:'xiaohong'}] arr2.filter(el=> arr1.some(item=> item.id === el.id)) //=> [{id: 2, name: 'xiaohong'}]
四、总结
总结: 数组去重的时候, 分为简单数组去重,及复杂的JSON数组去重, 简单的一维数组可以用new Set的唯一性去重, 还可以通过循环过程中, 通过对象的key的唯一性,将值作为key存到对象中, 判断对象中是否存在key,来判断是否要加入数组中。 或者是 通过indexOf 判断是否重复, 大体原理都比较类似, 对于复杂的JSON数组基本也是可以套简单数组的套路的, 在使用reduce、filter时可以帮我们简化代码,可以少引入几个变量, 但是可能会导致算法复杂度的提高(时间换空间), 需要在写时注意, 对于两个数组的去重, 通常是用 filter + some 两者进行配合去重