数组对象重复问题解析
项目中,我们常用的数组往往是数组对象,本文也就数组对象的重复与否,找出重复项,去掉重复项等来分析做法。
案例为:
var arr = [{"id":1,"name":"张三"},{"id":2,"name":"李四"},{"id":3,"name":"王五"},{"id":2,"name":"张三"}];
判断判断是否重复
var arr = [{"id":1,"name":"张三"},{"id":2,"name":"李四"},{"id":3,"name":"王五"},{"id":2,"name":"张三"}];
//用arr的id生成一个新的数组
const newArr = arr.map(value => value.name)
//将这个数组去重
const DuplicateDelete = new Set(newArr)
//判断两个数组的长度是否相等
if([...DuplicateDelete].length === arr.length){
console.log('没有重复')
}else{
console.log('重复了')
}
找出重复项
//接着以上代码
let duplicates = newArr
DuplicateDelete.forEach((item) => {
const i = duplicates.indexOf(item)
duplicates = duplicates
.slice(0, i)
.concat(duplicates.slice(i + 1, duplicates.length))
//首次出现的排除,剩下的整合成新数组。最后只剩下非首次出现的,就是重复的item会组成一个新数组。
})
console.log(duplicates)
// 结果为"张三"
其他数组对象去重方法
//用reduce去重重复项
let obj = {};
arr = arr.reduce(function(item, next) {
obj[next.name] ? '' : obj[next.name] = true && item.push(next); //如果name为'',放入next中,已经存在的就跳过了
return item;
}, []);
console.log(arr);
对象数组去重的实际应用
const arr1 = [
{time: '二季度', value: 14,type:'financial'},
{time: '三季度', value: 20,type:'financial'},
{time: '四季度', value: 10,type:'financial'},
]
const arr2 = [
{time: '二季度', value: 36,type:'manage'},
{time: '三季度', value: 45,type:'manage'},
{time: '四季度', value: 49,type:'manage'},
]
假设以上数据,我们需要将每一个对象的value进行相加,变成如下数组:
const arrCount = [
{time: '二季度', count: 50},
{time: '三季度', count: 65},
{time: '四季度', count: 59}
]
也即将每一项的value进行相加,得到每一个季度的value之和。我们应当如何封装一个方法?
这里有两种方式,一种方法针对两个数组,另一种则针对两个以上的数组。
方法一
//id表示唯一标识,value表示你要操作的值
function count(arr1,arr2,id,value){
const result = []
arr1.forEach(i =>{
arr2.forEach(e =>{
return i[id] === e[id] ? result.push({[id]:i[id],'count':i[value]+e[value]}) : null
})
})
}
这种方法利用双循环嵌套,对两个数组分别遍历,可以直接拿到结果,返回新数组
方法二
既然第一种方式可以直接解决此问题,那么为什么还要封装两个数组以上的方法呢?
这是因为,我们封装方法必须能够针对多数情况的,在实际项目中,往往需要考虑更复杂的情况。假设有三个数组,方法一便无法执行,因为其返回的结果不能再同第三个数组继续计算。你可以看看上面 arrCount
和 arr1
、arr2
的区别就懂了。
上代码:
首先,将你需要进行计算的数组完全合并
const arr = arr1.concat(arr2)
这样做的好处是,无论你有多少个数组,都能进行统一的处理,不必如 方法一 一样只能计算两个就匆匆返回结果。
其次,多个内部对象属性一样的数组合并,很多属性肯定是重复的,如arr1、arr2合并,属性time: '二季度'
就会有两个数据。我们选定要去掉的这个数据,将之命为参数id
传入,其次是需要进行计算的value:
function arrCount(arr,id,value){
//拿到所有id属性重复的组合
//就像这样排列:[{time: '二季度', value: 14,type:'financial'},{time: '二季度', value: 36,type:'manage'}]
let count = []
arr.forEach((i,index1)=>{
let duplicate = []
duplicate.push(i)
arr.forEach((e,index2) =>{
if (i[id] === e[id] && index1 !== index2 ){
duplicate.push(e)
}
})
//直接取到每个组合中value的和,并组合成自己想要的数组,放入count中
//我想要的:[{time:'二季度',count:50}....]
let result = duplicate.reduce((a,b) => a + b[value],0)
count.push({[id]:i[id],'count':result})
})
//去除重复项(很重要的一步)
let obj = {};
count = count.reduce((item, next) => {
!obj[next[id]] ? obj[next[id]] = item.push(next) : null ;
return item;
}, []);
return count
}
小结
对于数组对像的操作,其本质在于遍历时拿到数组对象中的某一对键值对来进行操作。
补充情景
var data = [
{itemID:1, amount: 1},
{itemID:1, amount: 2},
{itemID:1, amount: 2},
{itemID:2, amount: 2},
{itemID:3, amount: 2},
{itemID:3, amount: 9},
{itemID:3, amount: 2},
{itemID:3, amount: 18},
{itemID:2, amount: 10},
{itemID:1, amount: 2},
{itemID:1, amount: 20},
]
以上数据去重,同时取amount较大的. 常规方法:
function handleUnique(arr){
let keyList = []
let resultList = []
arr.map(item =>{
let index = keyList.indexOf(item.itemID)
if(index === -1){
keyList.push(item.itemID)
resultList.push(item)
}else{
let currentData = resultList[index]
if(item.amount > currentData.amount){
resultList[index] = item
}
}
})
return resultList;
}
handleUnique(data)
牛一点的可以利用分组链式写法:
const handleUnique = [...new Set(data.map(item => item.itemID))]
.map(item => data.filter(subItem => subItem.itemID === item))
.map(item => item.sort((a, b) => a.amount < b.amount))
.map(item => item[item.length - 1]);