Javascript系列——对象元素的数组去重实现

概要

这是一篇记录文,记录数组操作对象去重的实现。

需求

有这样一个数组


[{
_id: 123,
name: '张三'
},{
_id: 124,
name: '李四'
},{
_id: 123,
name: '张三'
}]

实际上我们只需要


[{
_id: 123,
name: '张三'
},{
_id: 124,
name: '李四'
}]

去重

简单数组的去重


Array.from(new Set([1,1,2,3,4,4])) // [1,2,3,4]

以对象为元素的数组去重

和数组相关的算法多种多样,在你以为自己已经掌握数组之后,会发现很多和数组相关的算法仍旧很复杂。

下面我将讲述一个入门等级的数组算法,解决上面提出的需求。

1、定义一个函数removeRepeat,它需要传入2个参数,arr表示需要去重的数组,field表示需要比较的key。比如我们的需求是比较 _id 是否有重复。


function removeRepeat(arr, field){
return arr
}

2、需要一个空数组,用来存储每个对象元素中field对应的value。


let s = []
for(let v of arr){
s.push(v[field])
}
//s = [123, 124, 123]

3、将所有field的值存到数组之后,它们的下标一一对应原数组的下标(这点很重要),接着我们需要2个对象集合,result用来存储s里遍历出来的元素,如果有重复,就将重复的元素丢到reSet对象里面。


let result = {}, reSet = {}
for(let i=0,len=s.length;i<len;i++){
if(!result[s[i]] && result[s[i]] !== 0) {
//如果result不存在当前的key并且它不为0时
result[s[i]] = i
} else {
reSet[s[i]] = i
}
}
// result = {123: 0, 124: 1} 这是去重重复后的元素
// reSet = {123: 2} 我们将重复的元素123作为key,它的下标2作为value。

4、上一步得到了result和reSet2个对象,那么,我们该用哪个对象来处理原数组的去重呢?只需要reSet,reSet记录了要去重的对象所在的下标,那么可以直接用splice干掉它。


for(let key in reSet){
arr.splice(reSet[key], 1)
}
/*
arr = [{
_id: 123,
name: '张三'
},{
_id: 124,
name: '李四'
}]
*/

5、说明

关键的第3和4步,都是用对象来处理,这样做的好处是时间复杂度可以达到O(1),如果用数组来保存,则需要2个for循环,时间复杂度变成了O(n²)。

完整源码


function removeRepeat(arr, field){
let s = [], result = {}, reSet = {}
for(let v of arr){
s.push(v[field])
}
for(let i=0,len=s.length;i<len;i++){
if(!result[s[i]] && result[s[i]] !== 0) {
result[s[i]] = i
} else {
reSet[s[i]] = i
}
}
for(let key in reSet){
arr.splice(reSet[key], 1)
}
return arr
} // removeRepeat(arr, '_id')

补充

受到各路大神的解法影响,我也针对上面代码的不足做了修改。

1、更简洁的代码。

2、支持多个重复对象的去重,缺点是会改变原来的排序。


const removeRepeat = (arr, field) => {
let s = {}
for(let i=0,len=arr.length;i<len;i++){
s[arr[i][field]] = arr[i]
}
return Object.values(s)
}

总结

数组还有各种有趣的操作,也经常作为各大公司考察的题型之重,多练习和数组相关的算法会很有帮助。

原文地址:https://segmentfault.com/a/1190000012873968

上一篇:git push 时发生错误 error: src refspec master does not match any. error: failed to push some refs to


下一篇:mysql‘事件计划已关闭。事件只能在服务器启动并开启事件计划时才能处理。'的警告