对象数组的去重(涉及多个场景)
普通数组去重
利用 Set
// 方法一
function noRepeat(arr){
let s = new Set(arr);
let arr1 = [];
for(let item of s){
arr1.push(item);
}
return arr1;
}
// 方法二
function noRepeat(arr){
let s = new Set(arr);
let arr1 = [];
s.forEach(item => arr1.push(item));
return arr1;
}
// 方法三
function noRepeat(arr){
let s = new Set(arr);
return [... s];
}
// 方法四
function noRepeat(arr){
let s = new Set(arr);
// 数组中的Array.from():功能:能够把伪数组、集合转成数组类型;
return Array.from(s);
}
// 以前的方法 利用循环 实现数组去重
function noRepeat(arr){
for(var i = 0; i < arr.length; i++){
for(var j = i + 1; j < arr.length; j++){
if(arr[j] == arr[i]){
arr.splice(j, 1);
}
}
}
return arr;
}
let arr = [12, 23, 34, 55, 23, 12];
let arr2 = noRepeat(arr);
console.log(arr2);
普通数组去重的思路还有很多,发散一下思维吧
对象数组去重
工作中常用到的也是对象数组去重
场景一:从A表格中选择数据添加到B表格中,不能重复
-
场景描述:
某一销售订单的维护需要从采购订单列表中选择一条或者多条采购订单来进行新增或修改的操作,需求是销售订单与采购订单的关系可能是一对一的也可能是一对多的,要求是不能选择重复的采购订单; -
场景分析:
采购订单的唯一性一般都是通过单据id或者是采购id来确定 -
思路分析:
既然涉及唯一性,我们可以用对象的key(也就是键值对的键) 的唯一性的特性来解决这个问题;
let arr = [
{
id: '1',
name: '订单1'
},
{
id: '1',
name: '订单2'
},
{
id: '2',
name: '订单2'
},
{
id: '2',
name: '订单3'
},
]
对象数组去重的方法一:
/**
* 对象数组去重
* @param {array} arr,需要去重的数组
* @param {string} key,通过指定key值进行去重
* @returns {array} newArr,返回一个去重后的新数组
*/
function noRepeatArrOfObj(arr, key) {
let obj = {};
let newArr = [];
arr.forEach( item => {
if(!obj[item[key]]) {
newArr.push(item);
// 将数组行数据的指定的唯一值作为对象的key
obj[item[key]] = true
}
})
return newArr;
}
对象数组去重的方法二:
利用 对象 + reduce
/**
* 对象数组去重
* @param {array} arr,需要去重的数组
* @param {string} key,通过指定key值进行去重
* @returns {array} 返回一个去重后的新数组
*/
function noRepeatArrOfObj(arr, key){
let obj = {}
return arr.reduce((pre, item) => {
obj[item[key]] ? '' : obj[item[key]] = true && pre.push(item)
return pre
},[])
}
对象数组去重的方法三:
利用 Map + filter
/**
* 对象数组去重
* @param {array} arr,需要去重的数组
* @param {string} key,通过指定key值进行去重
* @returns {array} 返回一个去重后的新数组
*/
function noRepeatArrOfObj(arr, key){
const res = new Map();
return arr.filter((item) => !res.has(item[key]) && res.set(item[key], true));
}
测试结果展示
let list = noRepeatArrOfObj(arr, 'id')
let list2 = noRepeatArrOfObj(arr, 'name')
console.log('list', list)
console.log('list2', list2)
场景1的处理方式有很多,
- 本文主要阐述的是数组去重,所以使用去重的方法去处理的,从B列表中选中的数据一般都是数组的形式,假设数据中的id 为1的数据就是我们添加过的,然后又将B列表中的id相同为 1 的数据又添加进去,数据就会重复,所以在赋值给A列表之前可以进行去重处理,然后再赋值给A列表;
- 当然还有其他的方法处理这种场景的数据处理,比如在给A列表push 之前先通过唯一值判断A列表中是否存在,不存在则push 进去也是可以的;这个判断是否存在的方法也有很多:indexOf、includes……
除此外,数组去重的方法还可以扩展思路,场景二又是一种
场景二:列表多条重复数据,只显示其中任意一条
-
场景描述:
维护某一产品列表时,需通过多个条件(比如名称、产地、尺寸等)判断出重复的数据,但在重复的数据中只显示其中任意一条反馈出来给用户,让用户知道这里有重复的数据; -
场景分析:
一样的通过需求指定的值来判断并取出重复的数据,然后从重复的数据中再去重解决反馈信息的问题; -
思路分析:
和场景一差不多,既然涉及唯一性,我们可以用对象的key(也就是键值对的键) 的唯一性的特性来解决这个问题;
let arr = [
{
name: '产品1',
city: '江西',
size: '100cm'
},
{
name: '产品1',
city: '江西',
size: '100cm'
},
{
name: '产品2',
city: '江西',
size: '100cm'
},
{
name: '产品3',
city: '江西',
size: '100cm'
},
{
name: '产品3',
city: '江西',
size: '100cm'
},
{
name: '产品4',
city: '江西',
size: '100cm'
},
]
// 1、先将重复的数据通过对象的键的方式筛出来
let list = []
let obj = {}
arr.forEach( item => {
let { name, city, size } = item
if (obj[name]) {
if ( obj[name]?.city == city && obj[name]?.size == size ) {
list.push(item)
}
} else {
obj[name] = { name, city, size }
}
})
// 2、可能存在多个重复的数据,进行去重即可,另一种去重的处理
let row = {}
list.forEach(item => {
let { name, city, size } = item
if (!row[name] && !row[city] && !row[size]) {
row[name] = { ...item }
}
})
console.log('newArr', Object.values(row))
场景二的去重没有进行函数封装,这种多字段控制的重复数据筛选再去重的需求可能比较少,封装的意义不大;
可以看到在第二步的时候进行对象数组的去重,我又换了一种方式去实现,只是这里是进行的多个条件判断的对象数组去重,原理差不多;
由此证明,对象数组去重的方法是有很多种思路的。
写在末尾
场景千千万,万变不离其中,明白其中的实现原理,针对不同的场景使用不同的处理方法,灵活多变才是我们希望达到的境界。
如有不足,望大家多多指点! 谢谢!