JS数组求并集交集和差集 (ES7/ES6/ES5)
集合的分类:
- 并集:以属于A或属于B的元素为元素的集合成为A与B的并(集)记作A∪B(或B∪A),读作“A并B”(或“B并A”),即A∪B={x|x∈A,或x∈B}
- 交集:以属于A且属于B的元素为元素的集合成为A与B的交(集)记作A∩B(或B∩A),读作“A交B”(或“B交A”),即A∩B={x|x∈A,且x∈B}
- 差集:以属于A而不属于B的元素为元素的集合成为A与B的差(集)记作A-B(或B∩A),读作“A减B”,即A-B={x∣x∈A,且x∉B}
方法一:
ES7新增了一个Array.prototype.includes
的数组方法,用于返回一个数组是否包含指定元素,结合filter
方法
// 并集
let union = a.concat(b.filter(v => !a.includes(v))) // [1,2,3,4,5]
// 交集
let intersection = a.filter(v => b.includes(v)) // [2]
// 差集
let difference = a.concat(b).filter(v => !a.includes(v) || !b.includes(v)) // [1,3,4,5]
方法二:
ES6中新增的一个Array.from
方法,用于将类数组对象和可遍历对象转化为数组。只要类数组有length
长度,基本都可以转化为数组。结合Set
结构实现数学集求解。
let aSet = new Set(a)
let bSet = new Set(b)
// 并集
let union = Array.from(new Set(a.concat(b))) // [1,2,3,4,5]
// 交集
let intersection = Array.from(new Set(a.filter(v => bSet.has(v)))) // [2]
// 差集
let difference = Array.from(new Set(a.concat(b).filter(v => !aSet.has(v) || !bSet.has(v)))) // [1,3,4,5]
方法三:
ES5可以利用filter
和indexOf
进行数学集操作,但是,由于indexOf
方法中NaN
永远返回-1,所以需要进行兼容处理。
不考虑NaN
// 并集
var union = a.concat(b.filter(function(v) {
return a.indexOf(v) === -1})) // [1,2,3,4,5]
// 交集
var intersection = a.filter(function(v){ return b.indexOf(v) > -1 }) // [2]
// 差集
var difference = a.filter(function(v){ return b.indexOf(v) === -1 }).concat(b.filter(function(v){ return a.indexOf(v) === -1 })) // [1,3,4,5]
考虑NaN
var aHasNaN = a.some(function(v){ return isNaN(v) })
var bHasNaN = b.some(function(v){ return isNaN(v) })
// 并集
var union = a.concat(b.filter(function(v) {
return a.indexOf(v) === -1 && !isNaN(v)})).concat(!aHasNaN & bHasNaN ? [NaN] : []) // [1,2,3,4,5]
// 交集
var intersection = a.filter(function(v){ return b.indexOf(v) > -1 }).concat(aHasNaN & bHasNaN ? [NaN] : []) // [2]
// 差集
var difference = a.filter(function(v){ return b.indexOf(v) === -1 && !isNaN(v) }).concat(b.filter(function(v){ return a.indexOf(v) === -1 && !isNaN(v) })).concat(aHasNaN ^ bHasNaN ? [NaN] : []) // [1,3,4,5]