
本文介绍如何使用一次 reduce 操作高效统计方向数组中每个元素的出现频次,并直接构建键值对对象,避免多次 filter 和重复 reduce,提升代码简洁性与执行效率。
本文介绍如何使用一次 reduce 操作高效统计方向数组中每个元素的出现频次,并直接构建键值对对象,避免多次 filter 和重复 reduce,提升代码简洁性与执行效率。
在处理方向路径(如 'n'、's'、'e'、'w')这类字符串数组时,常见需求是统计每种方向的出现次数,并以对象形式组织结果(例如 { n: 5, s: 5 })。原始代码通过两次 filter + reduce 分别处理 'n' 和 's',逻辑冗余、可扩展性差,且 acc++ 的误用还可能导致逻辑错误(如返回值非预期整数)。
更优解是单次遍历 + 单次 reduce:将累加器初始化为空对象 {},每次迭代根据当前方向(如 'n')动态更新对应属性值:
const walk = ['n', 's', 'n', 's', 'n', 's', 'n', 's', 'n', 's'];
const result = walk.reduce((acc, direction) => {
acc[direction] = (acc[direction] || 0) + 1;
return acc;
}, {});
console.log(result); // { n: 5, s: 5 }
✅ 优势说明:
- 时间复杂度 O(n):仅遍历一次数组;
- 空间友好:无需中间数组(省去 filter 生成的新数组);
- 可扩展性强:自动支持任意方向(如新增 'e' 或 'w' 不需修改逻辑);
- 语义清晰:acc[direction] || 0 确保首次访问时安全初始化为 0。
⚠️ 注意事项:
- 避免在 reduce 回调中直接修改外部对象(如原例中的 object),应始终返回累加器 acc;
- 若需标准化键名(如 'n' → 'north'),可在累加前映射:const map = { n: 'north', s: 'south' }; acc[map[direction]] = ...;
- 对于超大数据集,reduce 性能优于 forEach + 手动计数,因其函数式风格更易优化。
总结:善用 reduce 的累加器特性,结合对象属性动态访问,即可用一行核心逻辑替代多步操作,让统计逻辑既简洁又健壮。











