前言
对象数组常会进行取交集或者差集的操作。
假设有对象数组A和对象数组B,常规方法是比较B对象数组与A对象数组的差异,进而找到其差集或者交集。
但是现在面临的问题是数组A 和数组B中的对象可能不完全一样的情况,可采用以下方法解决该问题。
对象数组的定义
我们把对象数组A定义为长数组,其中包含的对象属性包括了name, age, weight
等三个属性;对象数组B定义为短数组,这里是指其元素个数小于数组A,其对象属性包括了name, age
等2个属性。
let wideArray = [{name: "luojiarui", age: 18, weight: 78}, {name: "zhangqirui", age: 28, weight: 70}];
let shortArray = [{name: "zhangqirui", age: 28}];
如果我们进行取对象的交集,那么就首先需要将对象属性进行重新处理为一样的属性,再进行差异比较。
最终的差集是:
finalArray = [{name: "luojiarui", age: 18, weight: 78}]
最终的交集是:
finalArray = [{name: "zhangqirui", age: 28, weight: 70}]
找出对象中的特定的属性
对象中特定属性的查找可以采用遍历对象的方法,我们这里采用reduce
。
首先我们看官方案例中计算,数组里所有值的和。这里采用累计器和当前值不断累积,最终计算出整个数组的和。注意在reduce的第二个参数中可以给出累加器的初始值,这里代码给出的是0。
var sum = [0, 1, 2, 3].reduce(function (accumulator, currentValue) {
return accumulator + currentValue;
}, 0);
// 和为 6
也可以写成箭头函数的形式:
var total = [ 0, 1, 2, 3 ].reduce(
( acc, cur ) => acc + cur,
0
);
这里,我封装了一个函数,名叫pick
。其用途是找出对象中指定的属性,且属性是必须包含。
function pick(obj, arr) {
// 参考网络上关于对象属性查找的方法,但是其没有指定必须包含该属性。
// return arr.reduce((iter, val) => (val in obj && (iter[val] = obj[val]), iter), {});
// 如果你打算提供一个初始值作为reduce()方法的第二个参数
return arr.reduce((iter, val) => {
if(val in obj) {
iter[val] = obj[val];
}else {
iter = {}
}
return iter;
}, {});
}
应用示例:
var object = { name: "ljr", age: 23, weight: 68};
var newObject = pick(object, ["name", "age"]); // 从对象中取到name和age属性。
// output: { name: "ljr", age: 23};
var newObject1 = pick(object, ["name", "price"]); // 从对象中取到name和price 属性。
// output : {}; // 由于对象中不存在price属性,因此返回值是空对象。
关于reduce的更多介绍可以查阅mdn。
Reduce() 方法讲解: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
差集和交集的计算
接下来通过遍历长数组元素,找出差集和交集。这里采用了很方便的一种比较方式,那就是使用indexOf。
但是该方法主要是应用于简单类型的数组或者字符串中,不能比较对象数组。
因此将对象数组转换为字符串进行比较。字符串比较的前提是,在前文中已经将对象数组进行重整,每个数组元素的属性已经是一致的。
indexOf 的原理是查找被查元素的索引,如果不能查到该元素则返回-1,如果能找到则返回该元素的索引值。
// 遍历长对象数组,同时取到两个对象数组的差集,交集
var substractedArray = [], intersectionArray = []; // 差集, 交集
wideArray.forEach( value => {
// 等于-1 表示 不存在,大于-1 表示存在
if(JSON.stringify(pickedShortArray)
.indexOf(JSON.stringify(pick(value,focusKeys))) == -1) {
substractedArray.push(value)
}else {
intersectionArray.push(value)
}
})
最终将查到的对象放入差集和交集数组中。
应用
默认传入参数为长对象数组,短对象数组,指定对象属性数组,差集或者交集方法。
默认对象属性数组为空,默认为差集方法。
对象属性数组可以通过wideArray[0].keys
传入。
let wideArray = [{name: "luojiarui", age: 18, weight: 78}, {name: "zhangqirui", age: 28, weight: 70}];
let shortArray = [{name: "zhangqirui", age: 28}];
var a = arrayFilter(wideArray, shortArray, [ "name", "age"], "substract");
console.log(a);
var b = arrayFilter(wideArray, shortArray, shortArray[0].keys, "intersect");
console.log(b);
附录
如下是源代码,感兴趣的同学可以拷贝进行测试。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>对象数组的交集并集</div>
<script>
let wideArray = [{name: "luojiarui", age: 18, weight: 78}, {name: "zhangqirui", age: 28, weight: 70}];
let shortArray = [{name: "zhangqirui", age: 28}];
var a = arrayFilter(wideArray, shortArray, [ "name", "age"], "substract");
console.log(a);
/**
* @desription
* @param
* @param
* @author 罗佳瑞
* @since 2021年10月18日
* */
function arrayFilter(wideArray, shortArray, focusKeys=[], method="substract"){
if(!Array.isArray(wideArray) || !Array.isArray(shortArray) ||
!Array.isArray(focusKeys) || focusKeys.length === 0 || method === "") {
return {
state: false,
info: "Param is error!",
result: []
}
}
// 判断传入的对象数组长度,如果两者长度不符合要求,那么进行交换
if(wideArray.length < shortArray.length ) {
var tempArray = wideArray;
wideArray = shortArray;
shortArray = tempArray;
}
// 定义返回参数
var finalArray = {
state: true,
info: method + "ing array successfully!",
result: []
};
// 对短数组进行遍历挑选,找到符合要求的对象属性
var pickedShortArray = [];
shortArray.forEach(element => {
var pickedObject = pick(element, focusKeys)
if(pickedObject != {}) pickedShortArray.push(pickedObject);
})
if(pickedShortArray.length == 0 ) return finalArray;
// 遍历长对象数组,同时取到两个对象数组的差集,交集
var substractedArray = [], intersectionArray = []; // 差集, 交集
wideArray.forEach( value => {
// 等于-1 表示 不存在,大于-1 表示存在
if(JSON.stringify(pickedShortArray)
.indexOf(JSON.stringify(pick(value,focusKeys))) == -1) {
substractedArray.push(value)
}else {
intersectionArray.push(value)
}
})
switch (method) {
case "substract":
finalArray.result = substractedArray;
break;
case "intersect":
finalArray.result = intersectionArray;
break
default:
finalArray.state = false;
finalArray.info = "method is error";
}
return finalArray;
}
function pick(obj, arr) {
// return arr.reduce((iter, val) => (val in obj && (iter[val] = obj[val]), iter), {});
// 如果你打算提供一个初始值作为reduce()方法的第二个参数
return arr.reduce((iter, val) => {
if(val in obj) {
iter[val] = obj[val];
}else {
iter = {}
}
return iter;
}, {});
}
</script>
</body>
</html>
如果您觉得上面的内容对您有帮助欢迎点赞、评论、转发!
更多内容请查阅作者博客:https://jiaruiblog.com
或者star
作者github: https://github.com/Jarrettluo?tab=repositories