JS 中数组的交集、并集、补集问题
一、背景
如图所示,list 里面有 9 个元素,用户选择的被放进了 selectedList,现在要求出剩余的元素组成的数组 result。实际就是求 selectedList 在 list 中的补集。
const list = [1,2,3,4,5,6,7,8,9];
const selectedList = [1,5,9];
function complement (a, b) {
return a.filter(value => !b.includes(value)).concat(b.filter(value => !a.includes(value)));
}
console.log(complement(list, selectedList)); // [2,3,4,6,7,8]
如果你第一次看到这段代码,一定会蒙圈,我也是。
没关系,接着往下看。
二、补集
1. 概念
补集是差集的一种,完整的说法是绝对差集。
2. 代码拆分
那我们就来拆一下代码:a.filter(value => !b.includes(value)).concat(b.filter(value => !a.includes(value)))
。.concat()
用于合并数组,因此,前后分别是某个数组,这是一个相加的过程。显然,我们弄清楚前面的数组是啥,后面的又是啥,那么整个就明白了。
请看图:
-
a.filter(value => !b.includes(value))
:遍历 a 数组,如果当前元素不在 b 数组中,那么就返回出来。(黑色箭头那一路,属于 a 但不属于 b。) -
b.filter(value => !a.includes(value))
:遍历 b 数组,如果当前元素不在 a 数组中,那么就返回出来。(蓝色箭头那一路,属于 b 但不属于 a。) -
所以,执行
complement(list, selectedList)
的过程:list 走黑色箭头,就得到[2,3,4,6,7,8]
,而 selectedList 走蓝色箭头,得到[]
,之后通过 concat 方法合并起来,得到结果 result =>[2,3,4,6,7,8]
。
3. 小结
综上,补集的写法还可以用 ES6 的剩余运算符来写:
function complement (a, b) {
return [...a.filter(value => !b.includes(value)), ...b.filter(value => !a.includes(value))];
}
三、差集
1. 概念
差集是相对差集的简称。直接看图。
2. 属于 a,不属于 b
下图所示,是由属于集合 A,但不属于集合 B 的元素组成的集合。
function diff (a, b) {
return a.filter(value => !b.includes(value));
}
3. 属于 b,不属于 a
下图所示,是由属于集合 B,但不属于集合 A 的元素组成的集合。
function diff (a, b) {
return b.filter(value => !a.includes(value));
}
四、交集
1. 概念
既属于集合 A,又属于集合 B 的元素,而没有其他元素的集合。
2. 代码
这没啥好说的,利用数组的 filter 方法遍历数组 a,如果当前遍历的元素也在数组 b 中,则将其放入新的数组中,最后返回新的数组即可。
function intersection (a, b) {
return a.filter(value => b.includes(value));
}
五、并集
1. 概念
集合 A 中所有元素加上集合 B 中所有元素组成的集合。
2. 代码
剩余运算符一把 solo。
function union (a, b) {
return Array.from(new Set([...a, ...b]));
}
六、对象数组中的常见集合
除了以上简单的情况以外,其实在真实开发中,操作对象数组更常见。
那么,如果列表里的每一个元素是一个对象呢?
const list = [
{id: '1', name: 'liuyi'},
{id: '2', name: 'chener'},
{id: '3', name: 'zhangsan'},
{id: '4', name: 'lisi'},
{id: '5', name: 'wangwu'},
{id: '6', name: 'zhaoliu'},
{id: '7', name: 'sunqi'},
{id: '8', name: 'zhouba'},
{id: '9', name: 'wujiu'},
{id: '10', name: 'zhengshi'},
];
const selectedList = [
{id: '1', name: 'liuyi'},
{id: '5', name: 'wangwu'},
{id: '9', name: 'wujiu'}
];
1. 补集
从所有订单中删除已付款的订单。
function complement(list, selectedList) {
return list.reduce(function (pre, cur) {
if (selectedList.every((item) => item.id !== cur.id)) {
pre.push({
name: cur.name
});
}
return pre;
}, []);
}
2. 交集
function intersection (a, b) {
let obj = {}
const arr = [...a, ...b];
return arr.reduce(function (pre, cur) {
obj.hasOwnProperty(cur.id) ? pre.push(cur) : (obj[cur.id] = true);
return pre;
}, []);
}
3. 并集
function union (a, b) {
let obj = {};
const arr = [...a, ...b];
return arr.reduce(function (pre, cur) {
if (!obj.hasOwnProperty(cur.id)) {
pre.push(cur);
}
obj[cur.id] = true;
return pre;
}, []);
}
七、小结
- 常见的集合主要有:交集、并集、补集(绝对差集)、差集(相对差集)。
添加我的微信:enjoy_Mr_cat,共同成长,卷卷群里等你 🤪。