
在 react native 中,需为数组中每个元素(除首项外)计算从首项到当前项的累计平均值,并在渲染时正确显示对应值。
实现该功能的关键在于:不为每个元素单独计算“相邻差值平均”,而是计算以首个数据为起点、逐项扩展的累计平均值(running average)。根据问题描述,输入 [3, 5, 6, 9] 应得到如下结果:
- 第 1 个元素(索引 0,volume=3)→ 不参与平均计算,约定输出 0 或留空(本文采用 0 保持长度一致);
- 第 2 个元素(索引 1,volume=5)→ (3 + 5) / 1 = 8?但注意题干逻辑:“between 3 and 5 and divide by 1” → 实际指前两项之和除以 间隔数(即项数减1);然而后续又说 “between 3, 5, 6 and divide by 2”,即 (3+5+6)/2 = 7 —— 这与常规累计平均不符。
⚠️ 经仔细分析原始描述与参考答案,真实意图是:
✅ 对第 i 个元素(0-indexed),计算前 i+1 个元素的和,再除以 i(即 i > 0 时用 sum / i)
→ 这等价于:跳过首项,将后续每个位置的平均值定义为“包含首项在内的前 i+1 个值的总和 ÷ 当前位置索引 i”。
例如:
- i = 0 → sum = 3, i = 0 → 未定义,返回 0(或跳过);
- i = 1 → (3 + 5) / 1 = 8;
- i = 2 → (3 + 5 + 6) / 2 = 14 / 2 = 7;
- i = 3 → (3 + 5 + 6 + 9) / 3 = 23 / 3 ≈ 7.67。
这正是参考答案中 runningVolumeAverage 函数所实现的逻辑(return i && sum / i)。
✅ 推荐实现方式(高效、可读、无副作用)
// 工具函数:生成累计平均值数组(长度与输入一致,首项为 0)
const calculateRunningAverages = (arr: { volume: number }[]): (number | null)[] => {
let sum = 0;
return arr.map(({ volume }, i) => {
sum += volume;
return i === 0 ? 0 : sum / i; // 首项返回 0;其余返回 sum / 当前索引(即“前 i+1 项和 ÷ i”)
});
};
// 在组件中使用
const averages = calculateRunningAverages(readings);
return (
{readings.map(({ id, date, volume }, index) => (
average: {averages[index] !== 0 ? averages[index].toFixed(2) : '—'}
))}
);⚠️ 注意事项
- 不要在 map 渲染循环内重复计算平均值:否则时间复杂度升至 O(n²),且易因闭包/状态不同步导致错误(如原代码中 for 循环覆盖 average 变量)。
- 索引 i 是关键:i 表示当前元素在数组中的位置(0 起始),sum / i 的分母是 i(非 i+1),严格匹配题目“divide by 1, divide by 2…”的要求。
- 精度处理:建议对浮点结果调用 .toFixed(2) 或使用 Math.round(x * 100) / 100 避免渲染 7.666666666666667。
-
空数组/单元素保护:生产环境建议增加边界判断:
if (arr.length === 0) return []; if (arr.length === 1) return [0];
✅ 总结
该需求本质是「带偏移的运行平均」——以首项为基准,每新增一项就更新一次「历史总和 ÷ 当前索引」。通过预计算 averages 数组并解耦渲染逻辑,既保证性能,又提升可维护性。最终效果:每个卡片显示其所在位置对应的动态平均值,语义清晰,符合业务预期。









