
本文介绍如何用一次 reduce 操作高效统计方向数组中各指令(如 'n'、's')出现频次,并写入对象,避免重复 filter 和 reduce,提升代码简洁性与性能。
本文介绍如何用一次 reduce 操作高效统计方向数组中各指令(如 'n'、's')出现频次,并写入对象,避免重复 filter 和 reduce,提升代码简洁性与性能。
在处理移动指令数组(如 ['n','s','n','s'])并统计各方向频次时,原始代码通过两次 filter + reduce 分别处理 'n' 和 's',不仅冗余,还导致数组被遍历三次(两次 filter + 两次 reduce 内部迭代),时间复杂度为 O(3n)。更优解是单次遍历 + 单次 reduce,直接按方向动态累加计数。
核心思路是将 reduce 的累加器(acc)设为初始空对象 {},每遇到一个方向(如 '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 }该写法简洁、高效且可扩展:若后续新增 'e'(东)、'w'(西)等方向,无需修改逻辑,自动支持新键。
⚠️ 注意事项:
- 使用 acc[direction] || 0 是为避免 undefined + 1 导致 NaN;也可用空值合并运算符 ??(ES2020+):acc[direction] ?? 0;
- 若需固定键名映射(如 'n' → 'north'),可在累加前做映射转换:
const dirMap = { n: 'north', s: 'south', e: 'east', w: 'west' }; walk.reduce((acc, d) => { const key = dirMap[d] || d; acc[key] = (acc[key] || 0) + 1; return acc; }, {}); - reduce 在此场景下语义清晰(“归约数组为单个统计对象”),比 forEach 更具函数式表达力,也便于链式组合或进一步转换。
总结:一次 reduce 完全替代多次过滤与归约,既降低时间开销,又增强代码可维护性与可读性——这才是函数式思维的真正实践。

















