将JS对象数组转为指定键分组对象:实现方法与工具推荐
刚好之前做过类似的需求,给你分享两种优雅的实现方式——原生JS手写和用Lodash简化,都能高效满足你的需求:
原生JS实现(无依赖)
核心思路是用Array.prototype.reduce遍历目标键数组,对每个键提取所有对象的对应值,再根据去重参数处理,最后组装成结果对象。这种方式不需要额外依赖,性能也很可观:
function groupByKeys(arr, keys, { unique = false } = {}) { return keys.reduce((result, key) => { // 提取所有对应键的值,可选过滤掉undefined/null(避免无效值混入) let values = arr.map(item => item[key]).filter(val => val != null); // 处理去重:用Set实现高效去重(仅对基础类型有效) if (unique) { values = [...new Set(values)]; } result[key] = values; return result; }, {}); }
使用示例
const testData = [ { id: 1, category: 'fruit', name: 'apple' }, { id: 2, category: 'fruit', name: 'banana' }, { id: 3, category: 'vegetable', name: 'apple' }, { id: 4, category: 'fruit', name: 'apple' } ]; // 不去重的情况 console.log(groupByKeys(testData, ['category', 'name'])); // 输出:{ category: ['fruit', 'fruit', 'vegetable', 'fruit'], name: ['apple', 'banana', 'apple', 'apple'] } // 去重的情况 console.log(groupByKeys(testData, ['category', 'name'], { unique: true })); // 输出:{ category: ['fruit', 'vegetable'], name: ['apple', 'banana'] }
Lodash/Underscore简化方案
如果你已经在用Lodash或者Underscore,那可以用它们的工具函数大幅简化代码,可读性拉满:
Lodash版本
import _ from 'lodash'; function groupByKeysLodash(arr, keys, { unique = false } = {}) { return _.fromPairs( keys.map(key => [ key, // 提取值 + 可选去重 unique ? _.uniq(_.map(arr, key)) : _.map(arr, key) ]) ); }
Underscore版本(和Lodash逻辑几乎一致)
import _ from 'underscore'; function groupByKeysUnderscore(arr, keys, { unique = false } = {}) { return _.object( keys.map(key => [ key, unique ? _.uniq(_.pluck(arr, key)) : _.pluck(arr, key) ]) ); }
这里用到的_.fromPairs(Lodash)/_.object(Underscore)负责把键值对数组转成对象,_.map/_.pluck提取对应键的值,_.uniq处理去重,一行核心逻辑就能搞定。
额外注意点
- 如果需要对**复杂类型(比如对象、数组)**去重,原生的
Set就失效了,这时候可以用Lodash的_.uniqWith配合_.isEqual:// 复杂类型去重示例(Lodash) unique ? _.uniqWith(_.map(arr, key), _.isEqual) : _.map(arr, key) - 如果希望保留
undefined或null值,只需要去掉原生实现里的.filter(val => val != null)即可。
内容的提问来源于stack exchange,提问作者mov
相关产品推荐
相关产品推荐

