数组对象重复问题解析

1,860 阅读4分钟

数组对象重复问题解析

项目中,我们常用的数组往往是数组对象,本文也就数组对象的重复与否,找出重复项,去掉重复项等来分析做法。

案例为:

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
     })
   })
}

这种方法利用双循环嵌套,对两个数组分别遍历,可以直接拿到结果,返回新数组

方法二

既然第一种方式可以直接解决此问题,那么为什么还要封装两个数组以上的方法呢?

这是因为,我们封装方法必须能够针对多数情况的,在实际项目中,往往需要考虑更复杂的情况。假设有三个数组,方法一便无法执行,因为其返回的结果不能再同第三个数组继续计算。你可以看看上面 arrCountarr1arr2 的区别就懂了。

上代码:

首先,将你需要进行计算的数组完全合并

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]);