如何在对象属性内按嵌套子属性进行二级分组?
保留主键的二级嵌套分组实现
我有一个包含多个键的对象,每个键对应一个值数组,需要在保留主键的前提下,按数组元素中的嵌套值进行分组。
输入数据
{ "foo1": [ {"name": "foo1","subpart": {"part": "bar1"}}, {"name": "foo1","subpart": {"part": "bar1"}}, {"name": "foo1","subpart": {"part": "bar2"}}, {"name": "foo1","subpart": {"part": "bar2"}}, {"name": "foo1","subpart": {"part": "bar3"}}, {"name": "foo1","subpart": {"part": "bar3"}} ], "foo2": [ {"name": "foo2","subpart": {"part": "bar1"}}, {"name": "foo2","subpart": {"part": "bar1"}}, {"name": "foo2","subpart": {"part": "bar2"}}, {"name": "foo2","subpart": {"part": "bar3"}}, {"name": "foo2","subpart": {"part": "bar3"}} ] }
期望输出
{ "foo1": { "bar1": [ {"name": "foo1","subpart": {"part": "bar1"}}, {"name": "foo1","subpart": {"part": "bar1"}} ], "bar2": [ {"name": "foo1","subpart": {"part": "bar2"}}, {"name": "foo1","subpart": {"part": "bar2"}} ], "bar3": [ {"name": "foo1","subpart": {"part": "bar3"}}, {"name": "foo1","subpart": {"part": "bar3"}} ] }, "foo2": { "bar1": [ {"name": "foo2","subpart": {"part": "bar1"}}, {"name": "foo2","subpart": {"part": "bar1"}} ], "bar2": [ {"name": "foo2","subpart": {"part": "bar2"}} ], "bar3": [ {"name": "foo2","subpart": {"part": "bar3"}}, {"name": "foo2","subpart": {"part": "bar3"}} ] } }
现有问题
当前的groupBy函数仅支持单级分组,直接调用会把所有数组元素合并到以subpart.part为键的分组中,丢失原有的foo1、foo2主键结构,不符合需求:
function groupBy<T>(arr: T[], fn: (item: T) => any) { return arr.reduce<Record<string, T[]>>((prev, curr) => { const groupKey = fn(curr); const group = prev[groupKey] || []; group.push(curr); return { ...prev, [groupKey]: group }; }, {}); } // 调用后会丢失原主键,不符合预期 const grouped = groupBy(data, (x) => x.subpart.part)
解决方案
需要遍历原对象的每个主键,对每个主键对应的数组单独执行分组操作,最终保留原结构。可以基于现有groupBy函数封装一个处理嵌套结构的函数:
// 保留原有的分组函数 function groupBy<T>(arr: T[], fn: (item: T) => any) { return arr.reduce<Record<string, T[]>>((prev, curr) => { const groupKey = fn(curr); prev[groupKey] = prev[groupKey] || []; prev[groupKey].push(curr); return prev; }, {}); } // 新增处理整个对象的函数,保留原主键 function groupNestedBy<T>(obj: Record<string, T[]>, fn: (item: T) => any) { const result: Record<string, Record<string, T[]>> = {}; for (const key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { result[key] = groupBy(obj[key], fn); } } return result; }
调用方式
const grouped = groupNestedBy(data, (x) => x.subpart.part);
该实现会遍历原对象的每个主键(如foo1、foo2),对每个主键下的数组执行嵌套值分组,最终输出与期望结构完全一致的结果。
内容的提问来源于stack exchange,提问作者Bouke Groenescheij
相关产品推荐
相关产品推荐

