在javascript开发中,数组差集指的是属于第一个数组但不属于第二个数组的元素组成的集合,是数据处理场景中非常常见的需求,比如筛选用户列表中未选中的用户、过滤已处理的数据等场景都会用到。
什么是数组差集
假设我们有两个数组arr1和arr2,数组差集的结果就是所有在arr1中出现,但是没有在arr2中出现的元素组成的新数组。比如arr1是[1,2,3,4],arr2是[2,4,5],那么差集结果就是[1,3]。
基础实现方法
使用filter和includes方法
这是最容易理解的实现方式,利用数组的filter方法遍历第一个数组,用includes判断当前元素是否存在于第二个数组中,不存在就保留。
// 定义两个数组 const arr1 = [1, 2, 3, 4, 5]; const arr2 = [2, 4, 6]; // 实现差集:arr1中存在,arr2中不存在的元素 const difference = arr1.filter(item => !arr2.includes(item)); console.log(difference); // 输出 [1, 3, 5]
这种方式的优点是代码简洁易懂,适合处理元素都是基本类型(数字、字符串、布尔值)的小数组。但是如果数组元素很多,includes方法每次都要遍历第二个数组,时间复杂度是O(n*m),性能会比较差。
使用Set优化性能
Set是es6引入的数据结构,它的has方法查找元素的时间复杂度是O(1),比数组的includes效率高很多,适合处理大数组的场景。
const arr1 = [1, 2, 3, 4, 5, 6]; const arr2 = [2, 4, 6, 8]; // 把第二个数组转成Set const arr2Set = new Set(arr2); // 过滤arr1中不在arr2Set里的元素 const difference = arr1.filter(item => !arr2Set.has(item)); console.log(difference); // 输出 [1, 3, 5]
处理重复元素的场景
上面的方法在arr1存在重复元素时,会保留重复的结果。比如arr1是[1,1,2,3],arr2是[2],差集结果是[1,1,3]。如果需要去重,可以在结果外面包一层Set再转回数组。
const arr1 = [1, 1, 2, 3, 3]; const arr2 = [2]; const arr2Set = new Set(arr2); // 先求差集再去重 const difference = [...new Set(arr1.filter(item => !arr2Set.has(item)))]; console.log(difference); // 输出 [1, 3]
处理引用类型元素的差集
如果数组的元素是对象这类引用类型,上面的方法会失效,因为引用类型的比较是看引用地址是否相同,而不是内容是否相同。这时候需要根据对象的某个唯一标识来判断,比如id。
const arr1 = [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' },
{ id: 3, name: '王五' }
];
const arr2 = [
{ id: 2, name: '李四' },
{ id: 4, name: '赵六' }
];
// 提取arr2中所有id组成Set
const arr2Ids = new Set(arr2.map(item => item.id));
// 过滤arr1中id不在arr2Ids里的元素
const difference = arr1.filter(item => !arr2Ids.has(item.id));
console.log(difference);
// 输出 [{ id: 1, name: '张三' }, { id: 3, name: '王五' }]
封装通用差集函数
我们可以把上面的逻辑封装成一个通用函数,支持传入自定义的比较键,方便不同场景使用。
/**
* 数组差集函数
* @param {Array} arr1 源数组
* @param {Array} arr2 对比数组
* @param {string|undefined} key 引用类型比较的键,基本类型不需要传
* @returns {Array} 差集结果
*/
function arrayDifference(arr1, arr2, key) {
if (key) {
// 处理引用类型,根据key判断
const arr2Keys = new Set(arr2.map(item => item[key]));
return arr1.filter(item => !arr2Keys.has(item[key]));
} else {
// 处理基本类型
const arr2Set = new Set(arr2);
return arr1.filter(item => !arr2Set.has(item));
}
}
// 测试基本类型
console.log(arrayDifference([1,2,3], [2,4])); // [1,3]
// 测试引用类型
const users1 = [{id:1},{id:2},{id:3}];
const users2 = [{id:2}];
console.log(arrayDifference(users1, users2, 'id')); // [{id:1},{id:3}]
不同方法的选择建议
如果是小数组且元素都是基本类型,使用filter+includes的方式代码更简洁;如果是大数组,优先使用Set+filter的方式提升性能;如果元素包含引用类型,一定要根据唯一标识来判断,不能直接用Set或者includes处理。
javascript数组差集数组操作Set修改时间:2026-06-22 21:15:51