JavaScript中用reduce实现数组分组统计,核心是初始化空对象{},遍历中按字段值(如item.category)作为key,对计数型用(acc[key] || 0) + 1,对分组收集型先确保acc[key] = acc[key] || []再push(item),多字段分组需构造唯一字符串复合key。

用 reduce 对数组元素做分组统计,核心是把空对象作为初始值,遍历中按分类条件更新对象属性(即各组的计数或子数组)。
按某个字段值分组并计数
适合统计每种类型、状态、类别出现的次数。关键是初始化为 {},每次根据当前项的字段值更新对应键的数值。
- 用
item[key]取分类依据(如item.type) - 用
acc[currentKey] = (acc[currentKey] || 0) + 1累加计数 - 避免直接写
acc[currentKey]++(会因 undefined 变 NaN)
const list = [
{ name: '苹果', category: '水果' },
{ name: '香蕉', category: '水果' },
{ name: '胡萝卜', category: '蔬菜' }
];
const countByCategory = list.reduce((acc, item) => {
const key = item.category;
acc[key] = (acc[key] || 0) + 1;
return acc;
}, {});
// → { 水果: 2, 蔬菜: 1 }
按条件分组并收集子数组
当需要把同类元素聚合成子数组(比如按奇偶、价格区间、是否完成),就把每个分组初始化为空数组,再用 push 添加。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 先确保目标分组存在:
acc[groupKey] = acc[groupKey] || [] - 再推入当前项:
acc[groupKey].push(item) - 返回
acc,保持链式结构
const numbers = [1, 2, 3, 4, 5];
const grouped = numbers.reduce((acc, n) => {
const key = n % 2 === 0 ? 'even' : 'odd';
acc[key] = acc[key] || [];
acc[key].push(n);
return acc;
}, {});
// → { odd: [1, 3, 5], even: [2, 4] }
多级嵌套分组(如按年+月分组)
可组合多个字段生成复合 key,例如 `${item.year}-${item.month}`,再按单层逻辑处理。
立即学习“Java免费学习笔记(深入)”;
- 构造唯一字符串 key,避免对象或数组作 key(会被转成
[object Object]) - 仍用空对象初始化,对每个复合 key 累加或收集
- 后续可用
Object.entries()或for...in遍历结果
const logs = [
{ time: '2023-05-01', msg: '登录' },
{ time: '2023-05-15', msg: '下单' },
{ time: '2023-06-10', msg: '退款' }
];
const byMonth = logs.reduce((acc, log) => {
const month = log.time.slice(0, 7); // '2023-05'
acc[month] = acc[month] || [];
acc[month].push(log);
return acc;
}, {});
// → { '2023-05': [...], '2023-06': [...] }
注意事项与技巧
reduce 分组看似简洁,但容易出错,注意这几处:
- 务必传入初始值(通常是
{}),否则第一次迭代时acc是第一个元素,类型错乱 - key 值要确保是字符串或基础类型;若用对象/函数作 key,实际会变成
[object Object] - 想保持插入顺序?现代 JS 中对象属性顺序基本按插入顺序,但更稳妥可用
Map替代对象 - 性能敏感场景:频繁读写对象属性比数组 push 略慢,但对千级数据无感

















