Skip to main content

如何实现数组的交、并、补、差集

filter 方法

var a = [1,2,3,4,5]
var b = [2,4,6,8,10]

//交集
var res = a.filter(function(v){ return b.indexOf(v) > -1 })

// ES6
let res = a.filter((v)=> b.indexOf(v) > -1 )

//差集
var res = a.filter(function(v){ return b.indexOf(v) == -1 })

let res = a.filter((v)=> b.indexOf(v) === -1 )

//补集
var res = a.filter(function(v){ return !(b.indexOf(v) > -1) })
.concat(b.filter(function(v){ return !(a.indexOf(v) > -1)}))

//并集
var res = a.concat(b.filter(function(v){ return !(a.indexOf(v) > -1)}));

Array 拓展

//数组功能扩展
//数组迭代函数
Array.prototype.each = function(fn){
fn = fn || Function.K;
var a = [];
var args = Array.prototype.slice.call(arguments, 1);
for(var i = 0; i < this.length; i++){
var res = fn.apply(this,[this[i],i].concat(args));
if(res != null) a.push(res);
}
return a;
};

//数组是否包含指定元素
Array.prototype.contains = function(suArr){
for(var i = 0; i < this.length; i ++){
if(this[i] == suArr){
return true;
}
}
return false;
}

//不重复元素构成的数组
Array.prototype.uniquelize = function(){
var ra = new Array();
for(var i = 0; i < this.length; i ++){
if(!ra.contains(this[i])){
ra.push(this[i]);
}
}
return ra;
};

//两个数组的交集
Array.intersect = function(a, b){
return a.uniquelize().each(function(o){return b.contains(o) ? o : null});
};

//两个数组的差集
Array.minus = function(a, b){
return a.uniquelize().each(function(o){return b.contains(o) ? null : o});
};

//两个数组的补集
Array.complement = function(a, b){
return Array.minus(Array.union(a, b),Array.intersect(a, b));
};

//两个数组并集
Array.union = function(a, b){
return a.concat(b).uniquelize();
};

var a = [1,2,3,4,5]
var b = [2,4,6,8,10]
console.log("数组a:", a);
console.log("数组b:", b);
console.log("a与b的交集:", Array.intersect(a, b));
console.log("a与b的差集:", Array.minus(a, b));
console.log("a与b的补集:", Array.complement(a, b));
console.log("a与b的并集:", Array.union(a, b))

ES5

ES5 可以利用 filterindexOf 进行数学集操作,但是,由于 indexOf 方法中 NaN 永远返回-1,所以需要进行兼容处理。

不考虑 NaN(数组中不含 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]

ES6 的 set 方式实现

ES6 中新增的一个 Array.from 方法,用于将类数组对象和可遍历对象转化为数组。只要类数组有 length 长度,基本都可以转化为数组。结合 Set 结构实现数学集求解。

比如: Array.from(arrayLike[, mapFn[, thisArg]])

var a = [1,2,3,4,5]
var b = [2,4,6,8,10]
console.log("数组a:", a);
console.log("数组b:", b);

var sa = new Set(a);
var sb = new Set(b);

// 交集
let intersect = a.filter(x => sb.has(x));

// 差集
let minus = a.filter(x => !sb.has(x));

// 补集
let complement = [...a.filter(x => !sb.has(x)), ...b.filter(x => !sa.has(x))];

// 并集
let unionSet = Array.from(new Set([...a, ...b]));

版本 2

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]

ES7

ES7 新增了一个 Array.prototype.includes 的数组方法,用于返回一个数组是否包含指定元素,结合 filter 方法。

比如: var boolean = array.includes(searchElement[, fromIndex])

// 并集
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]