由对象组成的数组如何去重?

需求:将下面data数组中id重复的数据去掉?


let data = [

    { id: 201801, name: '张三', age: 15, },

{ id: 201804, name: 'John', age: 18, },

{ id: 201802, name: '李四', age: 18, },

{ id: 201801, name: '张三', age: 15, },

{ id: 201805, name: 'Jack', age: 18, },

{ id: 201803, name: '王五', age: 10, },

{ id: 201805, name: 'Jack', age: 18, },

    { id: 201804, name: 'John', age: 18, },

{ id: 201805, name: 'Jack', age: 18, },

        ];


1、数组的reduce()方法

let hash = {}; 

data = data.reduce((preVal, curVal) => {

hash[curVal.id] ? '' : hash[curVal.id] = true && preVal.push(curVal); 

return preVal 

}, [])


通过console.log('1111', data, hash);查看结果:


可以看出新得到的data 数组中所有数据的id都是唯一的。


1.1、上述方法的实现思路

  利用reduce()方法的累积器作用,在对由对象组成的数组进行遍历时,通过对象hash来标记数组中每个元素id是否出现过,如果出现过,那么遍历到的当前元素则不会放入到累积器中,如果没有出现,则添加到累积器中,这样保证了最后返回值中每个数据id的唯一性。


1.2、关于数组的reduce()方法

官方解释:reduce()方法接收一个函数作为累积器,数组中的每个值从左到右开始合并,最后返回一个值。

我的理解:reduce()其实也就是对数组从左到右进行遍历,在遍历的同时按照回调函数中的方法进行处理,reduce()的特别之处是在于它每遍历一个元素之后会将这个元素放在累积器中累积起来,类似于收割机收小麦一样,从左往右收割,收割机中用来放收割好小麦的地方就类似于reduce()的累积器,最后满满收好的一大袋小麦就类似于reduce()的返回值。


语法:


array.reduce(callbackfunction, initialVal);

function callbackfunction(preVal, curVal, index, array){

//函数体

}


  数组的reduce()方法接收两个参数,callbackfunction回调函数和initialVal初始值;callbackfunction是必需项,initialVal是可选项;callbackfunction回调函数接收四个参数:

preVal —> 上一次调用回调函数返回的值,或者初始值initialVal;

curVal —> 数组中当前被处理的值;

index —> 当前的值在数组中的索引;

array —> 调用reduce()方法的数组;

callbackfunction函数中必须有返回值,也就是累积器,它每次的返回值都是下一次调用回调函数中的preVal值。


下面表格是上述数组对象去重时reduce()执行过程:

其中data 表示data数组,data[1] 表示data数组中的第一个对象,即{ id: 201801, name: '张三', age: 15, },data[2]表示data数组中的第二个对象,即{ id: 201804, name: 'John', age: 18, },依次类推。


preVal curVal index array返回值

第一次回调 [ ] data[1] 0 data [ data[1] ]

第二次回调 [ data[1] ] data[2] 1 data [ data[1], data[2] ]

第三次回调 [ data[1], data[2] ] data[3] 2 data [ data[1], data[2], data[3] ]

第四次回调 [ data[1], data[2], data[3] ] data[4] 3 data [ data[1], data[2], data[3] ]

第五次回调 [ data[1], data[2], data[3] ] data[5] 4 data [ data[1], data[2], data[3], data[5] ]

第六次回调 [ data[1], data[2], data[3], data[5] ] data[6] 5 data [ data[1], data[2], data[3], data[5], data[6] ]

第七次回调 [ data[1], data[2], data[3], data[5], data[6] ] data[7] 6 data [ data[1], data[2], data[3], data[5], data[6] ]

第八次回调 [ data[1], data[2], data[3], data[5], data[6] ] data[8] 7 data [ data[1], data[2], data[3], data[5], data[6] ]

第九次回调 [ data[1], data[2], data[3], data[5], data[6] ] data[9] 8 data [ data[1], data[2], data[3], data[5], data[6] ]

  从上面执行过程可以看出reduce()其实也就是遍历每个元素,只不过它在遍历下一个元素时会把上一次回调函数返回的值带入来进行相关操作。


2、for循环遍历

function removeRepeat(arr, key){

for(let i = 0; i < arr.length; i++) {

for(let j = i+1; j < arr.length; j++) {

if(arr[i][key] === arr[j][key]){

arr.splice(j, 1);

j = j-1;  // 关键,因为splice()删除元素之后,会使得数组长度减小,此时如果没有j=j-1的话,会导致相同id项在重复两次以上之后无法进行去重,且会错误删除id没有重复的项。

}

}

}

}

removeRepeat(data, 'id');


通过console.log('2222', data);查看结果:


可以看出新得到的data 数组中所有数据的id都是唯一的。


2.1、上述方法的实现思路

  利用for循环遍历数组,并将数组中的每一个元素与剩余元素一一进行比较,如果在剩余元素中出现id相同的项,则通过splice()方法将相同id项删除,这样在最终得到的数组中每个数据id将是唯一的。通过splice()方法删除元素后,会使得数组长度减小,为了实现去重应该执行j = j-1。上面将去重方法直接封装成函数removeRepeat,使用时可以直接调用该函数,并传入要去重的数组和唯一属性名。