背景
项目中经常有对两个数组的操作,涉及到一些数学中集合的运算.
集合的定义
集合定义:集合是指具有某种特定性质的具体的或抽象的对象汇总而成的集体。其中,构成集合的这些对象则称为该集合的元素
交集定义:由属于A且属于B的相同元素组成的集合,记作A∩B(或B∩A),读作“A交B”(或“B交A”),即A∩B={x|x∈A,且x∈B}, 如右图所示。注意交集越交越少。若A包含B,则A∩B=B,A∪B=A .
并集定义:由所有属于集合A或属于集合B的元素所组成的集合,记作A∪B(或B∪A),读作“A并B”(或“B并A”),即A∪B={x|x∈A,或x∈B},如下图所示。注意并集越并越多,这与交集的情况正相反 。
编码实战
简单数组
利用ES6中set数组的特性
const aArray = [1, 2, 3, 4, 5];
const bArray = [5, 6, 7, 8, 9];
/**
* @function 求两个数组的交集
* @description 数组为简单数组
* @returns {array} 正常的数组
* */
const intersection = (aArray, bArray) => {
const bArraySet = new Set(bArray);
const resultArray = aArray.filter(item => bArraySet.has(item));
return Array.from(resultArray);
}
/**
* @function 求两个数组的并集
* @description 数组为简单数组
* @returns {array} 正常的数组
* */
const union = (aArray, bArray) => {
const resultArray = new Set([...aArray, ...bArray]);
return Array.from(resultArray);
}
/**
* @function 求两个数组的差集;数组aArray相对于bArray所没有的
* @description 数组为简单数组
* @returns {array} 正常的数组
* */
const difference = (aArray, bArray) => {
const bArraySet = new Set(bArray);
const resultArray = aArray.filter(item => !bArraySet.has(item));
return Array.from(resultArray);
}
console.log('aArray: ', aArray);
console.log('bArray: ', bArray);
console.log('并集', union(aArray, bArray));
console.log('交集', intersection(aArray, bArray));
console.log('差集', difference(aArray, bArray));
定义正式集合操作
创建含有集合操作的子类
class XSet extends Set {
union(...sets) {
return XSet.union(this, ...sets)
}
intersection(...sets) {
return XSet.intersection(this, ...sets);
}
difference(set) {
return XSet.difference(this, set);
}
symmetricDifference(set) {
return XSet.symmetricDifference(this, set);
}
cartesianProduct(set) {
return XSet.cartesianProduct(this, set);
}
powerSet() {
return XSet.powerSet(this);
}
// 返回两个或更多集合的并集
static union(a, ...bSets) {
const unionSet = new XSet(a);
for (const b of bSets) {
for (const bValue of b) {
unionSet.add(bValue);
}
}
return unionSet;
}
// 返回两个或更多集合的交集
static intersection(a, ...bSets) {
const intersectionSet = new XSet(a);
for (const aValue of intersectionSet) {
for (const b of bSets) {
if (!b.has(aValue)) {
intersectionSet.delete(aValue);
}
}
}
return intersectionSet;
}
// 返回两个集合的差集
static difference(a, b) {
const differenceSet = new XSet(a);
for (const bValue of b) {
if (a.has(bValue)) {
differenceSet.delete(bValue);
}
}
return differenceSet;
}
// 返回两个集合的对称差集
static symmetricDifference(a, b) {
// 按照定义,对称差集可以表达为
return a.union(b).difference(a.intersection(b));
}
// 返回两个集合(数组对形式)的笛卡儿积
// 必须返回数组集合,因为笛卡儿积可能包含相同值的对
static cartesianProduct(a, b) {
const cartesianProductSet = new XSet();
for (const aValue of a) {
for (const bValue of b) {
cartesianProductSet.add([aValue, bValue]);
}
}
return cartesianProductSet;
}
// 返回一个集合的幂集
static powerSet(a) {
const powerSet = new XSet().add(new XSet());
for (const aValue of a) {
for (const set of new XSet(powerSet)) {
powerSet.add(new XSet(set).add(aValue));
}
}
return powerSet;
}
}
const aArray = [1, 2, 3, 4, 5];
const bArray = [5, 6, 7, 8, 9];
/**
* @function 求两个数组的交集
* @description 数组为简单数组
* @returns {array} 正常的数组
* */
const intersection = (aArray, bArray) => {
const aArrayXSet = new XSet(aArray);
const bArrayXSet = new XSet(bArray);
const resultArray = aArrayXSet.intersection(bArrayXSet);
return Array.from(resultArray);
}
/**
* @function 求两个数组的并集
* @description 数组为简单数组
* @returns {array} 正常的数组
* */
const union = (aArray, bArray) => {
const aArrayXSet = new XSet(aArray);
const bArrayXSet = new XSet(bArray);
const resultArray = aArrayXSet.union(bArrayXSet);
return Array.from(resultArray);
}
/**
* @function 求两个数组的差集;数组aArray相对于bArray所没有的
* @description 数组为简单数组
* @returns {array} 正常的数组
* */
const difference = (aArray, bArray) => {
const aArrayXSet = new XSet(aArray);
const bArrayXSet = new XSet(bArray);
const resultArray = aArrayXSet.difference(bArrayXSet);
return Array.from(resultArray);
}
console.log('aArray: ', aArray);
console.log('bArray: ', bArray);
console.log('并集', union(aArray, bArray));
console.log('交集', intersection(aArray, bArray));
console.log('差集', difference(aArray, bArray));
对象数组
利用ES6中set数组的特性
const aArray = [
{
id: 1,
desc: 'Number'
},
{
id: 2,
desc: 'Number'
},
{
id: 3,
desc: 'Number'
},
{
id: 4,
desc: 'Number'
},
{
id: 5,
desc: 'Number'
}
];
const bArray = [
{
id: 5,
desc: 'Number'
},
{
id: 6,
desc: 'Number'
},
{
id: 7,
desc: 'Number'
},
{
id: 8,
desc: 'Number'
},
{
id: 9,
desc: 'Number'
}
];
/**
* @function 求两个数组的交集
* @description 数组为简单数组
* @returns {array} 正常的数组
* */
const intersection = (aArray, bArray) => {
const bArraySet = new Set(bArray);
const resultArray = aArray.filter(item => bArraySet.has(item));
return Array.from(resultArray);
}
/**
* @function 求两个数组的并集
* @description 数组为简单数组
* @returns {array} 正常的数组
* */
const union = (aArray, bArray) => {
const resultArray = new Set([...aArray, ...bArray]);
return Array.from(resultArray);
}
/**
* @function 求两个数组的差集;数组aArray相对于bArray所没有的
* @description 数组为简单数组
* @returns {array} 正常的数组
* */
const difference = (aArray, bArray) => {
const bArraySet = new Set(bArray);
const resultArray = aArray.filter(item => !bArraySet.has(item));
return Array.from(resultArray);
}
/**
* @function 获取集合运算的结果数组
* @param {string} key 数组对象的唯一标识
* @param {function} functionAction 需要调用的函数
* @param {array} aArray
* @param {array} bArray
* @returns {array} 正常的数组
* */
const getResultArray = (key, functionAction, aArray, bArray) => {
const aArraySimple = aArray.map(i => i[key]); // 根据唯一标识对象数组转换为简单数组
const bArraySimple = bArray.map(i => i[key]);
const allData = [...aArray, ...bArray];
const resultArraySimple = Array.from(functionAction(aArraySimple, bArraySimple));
return resultArraySimple.map(i => allData.find((j) => j[key] === i));
}
console.log('aArray: ', aArray);
console.log('bArray: ', bArray);
console.log('并集', getResultArray('id', union, aArray, bArray));
console.log('交集', getResultArray('id', intersection, aArray, bArray));
console.log('差集', getResultArray('id', difference, aArray, bArray));
定义正式集合操作
class XSet extends Set {
union(...sets) {
return XSet.union(this, ...sets)
}
intersection(...sets) {
return XSet.intersection(this, ...sets);
}
difference(set) {
return XSet.difference(this, set);
}
symmetricDifference(set) {
return XSet.symmetricDifference(this, set);
}
cartesianProduct(set) {
return XSet.cartesianProduct(this, set);
}
powerSet() {
return XSet.powerSet(this);
}
// 返回两个或更多集合的并集
static union(a, ...bSets) {
const unionSet = new XSet(a);
for (const b of bSets) {
for (const bValue of b) {
unionSet.add(bValue);
}
}
return unionSet;
}
// 返回两个或更多集合的交集
static intersection(a, ...bSets) {
const intersectionSet = new XSet(a);
for (const aValue of intersectionSet) {
for (const b of bSets) {
if (!b.has(aValue)) {
intersectionSet.delete(aValue);
}
}
}
return intersectionSet;
}
// 返回两个集合的差集
static difference(a, b) {
const differenceSet = new XSet(a);
for (const bValue of b) {
if (a.has(bValue)) {
differenceSet.delete(bValue);
}
}
return differenceSet;
}
// 返回两个集合的对称差集
static symmetricDifference(a, b) {
// 按照定义,对称差集可以表达为
return a.union(b).difference(a.intersection(b));
}
// 返回两个集合(数组对形式)的笛卡儿积
// 必须返回数组集合,因为笛卡儿积可能包含相同值的对
static cartesianProduct(a, b) {
const cartesianProductSet = new XSet();
for (const aValue of a) {
for (const bValue of b) {
cartesianProductSet.add([aValue, bValue]);
}
}
return cartesianProductSet;
}
// 返回一个集合的幂集
static powerSet(a) {
const powerSet = new XSet().add(new XSet());
for (const aValue of a) {
for (const set of new XSet(powerSet)) {
powerSet.add(new XSet(set).add(aValue));
}
}
return powerSet;
}
}
const aArray = [
{
id: 1,
desc: 'Number'
},
{
id: 2,
desc: 'Number'
},
{
id: 3,
desc: 'Number'
},
{
id: 4,
desc: 'Number'
},
{
id: 5,
desc: 'Number'
}
];
const bArray = [
{
id: 5,
desc: 'Number'
},
{
id: 6,
desc: 'Number'
},
{
id: 7,
desc: 'Number'
},
{
id: 8,
desc: 'Number'
},
{
id: 9,
desc: 'Number'
}
];
/**
* @function 求两个数组的交集
* @description 数组为简单数组
* @returns {array} 正常的数组
* */
const intersection = (aArray, bArray) => {
const aArrayXSet = new XSet(aArray);
const bArrayXSet = new XSet(bArray);
const resultArray = aArrayXSet.intersection(bArrayXSet);
return Array.from(resultArray);
}
/**
* @function 求两个数组的并集
* @description 数组为简单数组
* @returns {array} 正常的数组
* */
const union = (aArray, bArray) => {
const aArrayXSet = new XSet(aArray);
const bArrayXSet = new XSet(bArray);
const resultArray = aArrayXSet.union(bArrayXSet);
return Array.from(resultArray);
}
/**
* @function 求两个数组的差集;数组aArray相对于bArray所没有的
* @description 数组为简单数组
* @returns {array} 正常的数组
* */
const difference = (aArray, bArray) => {
const aArrayXSet = new XSet(aArray);
const bArrayXSet = new XSet(bArray);
const resultArray = aArrayXSet.difference(bArrayXSet);
return Array.from(resultArray);
}
/**
* @function 获取集合运算的结果数组
* @param {string} key 数组对象的唯一标识
* @param {function} functionAction 需要调用的函数
* @param {array} aArray
* @param {array} bArray
* @returns {array} 正常的数组
* */
const getResultArray = (key, functionAction, aArray, bArray) => {
const aArraySimple = aArray.map(i => i[key]); // 根据唯一标识对象数组转换为简单数组
const bArraySimple = bArray.map(i => i[key]);
const allData = [...aArray, ...bArray];
const resultArraySimple = Array.from(functionAction(aArraySimple, bArraySimple));
return resultArraySimple.map(i => allData.find((j) => j[key] === i));
}
console.log('aArray: ', aArray);
console.log('bArray: ', bArray);
console.log('并集', getResultArray('id', union, aArray, bArray));
console.log('交集', getResultArray('id', intersection, aArray, bArray));
console.log('差集', getResultArray('id', difference, aArray, bArray));