JavaScript 实现对象数组按 Description 分组合并为 Code 数组
原代码异常根因
你调用groupBy时的传参存在错误:
- 传入的第二个参数是
array.forEach(document => document.Description),这个表达式会立即执行一次数组遍历,但forEach方法本身没有返回值,最终表达式的结果是undefined - 进入
groupBy内部逻辑后,因为criteria是undefined,既不是可执行的取值函数,也不是对象的合法属性名,计算出的分组键值永远是item[undefined]也就是undefined,最终所有元素都会被归集到undefined这一个分组下,出现你描述的异常结果。
最优实现方案
你编写的groupBy通用分组函数本身逻辑没有问题,只需要修正传参方式,再补充一步结构转换即可实现需求,全程不需要引入第三方库,时间复杂度为O(n),无额外性能损耗:
1. 修正groupBy的入参
按照groupBy原本的设计,criteria支持两种合法传法:
- 直接传入需要分组的属性名字符串:
groupBy(array, 'Description') - 传入自定义的取值函数:
groupBy(array, item => item.Description)
注意不要在传参位置执行任何没有返回值的数组方法(比如forEach),这类方法执行后只会返回undefined,无法作为分组依据
2. 分组结果的结构转换
修正传参后,groupBy返回的是形如{ Invoice: [匹配的对象列表], Credit: [匹配的对象列表], Backup: [匹配的对象列表] }的扁平对象,需要遍历每个分组,提取组内所有Code值组装成数组,拼成要求的输出结构:
var groupBy = function (arr, criteria) { return arr.reduce(function (obj, item) { // 判断criteria类型,生成分组键 var key = typeof criteria === 'function' ? criteria(item) : item[criteria]; // 初始化分组数组 if (!obj.hasOwnProperty(key)) { obj[key] = []; } // 将当前元素归入对应分组 obj[key].push(item); return obj; }, {}); }; var array = [ {"Code": 101, "Description": "Invoice"}, {"Code": 102, "Description": "Credit"}, {"Code": 103, "Description": "Credit"}, {"Code": 111, "Description": "Invoice"}, {"Code": 112, "Description": "Credit"}, {"Code": 113, "Description": "Credit"}, {"Code": 182, "Description": "Backup"} ]; // 第一步:按Description字段完成分组 const groupedMap = groupBy(array, 'Description'); // 第二步:将分组Map转换为目标输出结构 const result = Object.entries(groupedMap).map(([desc, groupItems]) => ({ Description: desc, Code: groupItems.map(item => item.Code) })); console.log(result);
运行上述代码得到的输出和你给出的目标结构完全匹配,并且代码拆分了独立的分组、结构转换逻辑,后续如果需要调整分组字段、修改Code的聚合规则,不需要改动通用分组函数的核心逻辑,可维护性更强。
内容的提问来源于stack exchange,提问作者Martin Scola
相关产品推荐
相关产品推荐

