用 reduce() 实现多级分组的核心是构建嵌套对象树,逐层根据字段值创建键,叶子节点存储匹配项数组;支持默认值、聚合计算与自定义归约逻辑。

用 reduce() 实现多级分组,核心是把每一层分组键作为嵌套对象的路径,逐层累积数据。不是简单套一层 reduce,而是让 accumulator 持有树状结构,并在每一步根据当前层级的键决定往哪一层插入。
理解多级分组的数据结构
比如对用户数组按 country → city → status 分组,结果应类似:
{
"CN": {
"Beijing": {
"active": [{...}],
"inactive": [{...}]
},
"Shanghai": { ... }
},
"US": { ... }
}
这本质是一个深度为 3 的嵌套对象(或 Map),每层 key 来自对应字段值,叶子节点是匹配该路径的所有元素数组。
基础版:固定层级的 reduce 实现
假设分组路径是字符串数组,如 ["country", "city", "status"],可这样写:
遍历每个 item,用 reduce 沿路径创建嵌套结构,最后一层存数组:
- 初始化 accumulator 为一个空对象
- 对每个分组键(如
"country"),取 item 对应值作为下一层 key - 若该 key 不存在,就初始化为对象(或 Map);继续下一层
- 到达最后一层时,将 item 推入对应数组(若无则新建)
function groupByNested(arr, keys) {
return arr.reduce((acc, item) => {
let cursor = acc;
for (let i = 0; i 增强版:支持函数键、默认值与聚合操作
实际中常需更灵活的能力,例如:
- 键可以是访问器函数(如
u => u.profile?.region || 'unknown') - 某层缺失字段时提供默认值(避免
undefined作 key) - 不只收集原始项,还能做计数、求和等聚合(如
{ count: 1, total: item.price })
这时可在 reduce 内部封装一个“路径导航器”,并允许传入 reducer 函数替代默认的 push:
function groupByNested(arr, keys, reducer = (group, item) => { group.push(item); }) {
return arr.reduce((acc, item) => {
let cursor = acc;
for (let i = 0; i // 示例:统计每城市各状态人数
const result = groupByNested(users, ['country', 'city', 'status'], (group, item) => {
group.count = (group.count || 0) + 1;
});实用技巧与注意事项
避免常见坑,提升健壮性:
-
键安全处理:用
?? 'null'或String(...)防止undefined/null导致意外分组 -
性能考虑:深层嵌套对象查起来快,但 JSON 序列化/深比较慢;高频读取场景可用
Map替代对象(需微调初始化逻辑) - 动态层级:keys 数组长度即分组深度,完全动态,无需改函数体
-
组合使用:可先用
filter预筛数据,再传给groupByNested,逻辑更清晰
不复杂但容易忽略。











