JavaScript中如何高效提取对象数组属性并去重分组?
高效实现按属性分组并去重的方案
嘿,这个需求我之前处理类似数据集的时候也碰到过,要说最高效的实现方式,那肯定是结合数组reduce遍历 + Set自动去重的组合方案了——毕竟Set的去重操作是O(1)级别的,整体能把时间复杂度控制在O(n),比用数组includes做去重的O(n²)高效太多,尤其是数据量上去之后差距会特别明显。
核心实现代码
const fruits = [ { name: 'apple', color: 'red', hasPeel: false }, { name: 'banana', color: 'yellow', hasPeel: true }, { name: 'orange', color: 'orange', hasPeel: true }, { name: 'strawberry', color: 'red', hasPeel: false } ]; // 第一步:用reduce遍历数组,用Set收集每个属性的所有值(自动去重) const groupedWithSet = fruits.reduce((acc, currentFruit) => { // 遍历当前水果对象的每个属性键值对 Object.entries(currentFruit).forEach(([key, value]) => { // 如果结果对象里还没这个属性,就初始化一个空Set if (!acc[key]) { acc[key] = new Set(); } // 把值加入Set,自动忽略重复项 acc[key].add(value); }); return acc; }, {}); // 第二步:把所有Set转换成数组,得到最终结果 const finalResult = Object.fromEntries( Object.entries(groupedWithSet).map(([key, valueSet]) => [key, Array.from(valueSet)]) ); console.log(finalResult); // 输出:{ name: ['apple', 'banana', 'orange', 'strawberry'], color: ['red', 'yellow', 'orange'], hasPeel: [true, false] }
为什么这个方案高效?
- 只需要遍历原数组一次(
reduce的遍历),每个对象的属性遍历是固定次数(这里是3个属性),整体时间复杂度是O(n),n是原数组的元素个数 Set的add操作是O(1)的,对比用数组includes判断重复(每次需要遍历数组,时间复杂度O(m),m是当前数组长度),在数据量大的时候性能提升非常显著- ES6+的
Set会保留元素的插入顺序,所以最终数组里的元素顺序和原数组中首次出现的顺序一致,符合需求预期
简化版实现(现代浏览器兼容)
如果你的运行环境支持ES2020+的空值合并运算符(??=),可以把代码简化成两步合一:
const fruits = [/* 你的数组数据 */]; const finalResult = fruits.reduce((acc, currentFruit) => { Object.entries(currentFruit).forEach(([key, value]) => { // 空值合并赋值:如果acc[key]不存在,就初始化Set acc[key] ??= new Set(); acc[key].add(value); }); return acc; }, {}); // 把Set转为数组 Object.keys(finalResult).forEach(key => finalResult[key] = Array.from(finalResult[key]));
注意事项
- 这个方案仅适用于基础类型的属性值(字符串、数字、布尔值等),如果属性值是引用类型(比如对象、数组),
Set会比较引用地址,没法直接去重,需要额外处理 - 如果需要兼容非常老的浏览器(比如IE),需要把
Object.entries、Set这些ES6特性转译成ES5语法,或者用polyfill
内容的提问来源于stack exchange,提问作者Cappyccino
相关产品推荐
相关产品推荐

