如何为MySQL查询结果计算6期移动平均及验证代码正确性?
6周期移动平均实现的合理性分析
首先先指出你代码里的几个小问题,再聊聊整体实现的合理性:
先看代码里的明显问题
- 键名重复错误:你在
array_push里写了两次'hours_open',第二个应该是'hours_closed',不然会覆盖掉前面的hours_open值:// 错误写法 array_push($results, [ 'hours_open' => $data[$i]['hours_open'], 'hours_open' => $data[$i]['hours_closed'], // 这里键名重复了! 'ma_hours_closed' => $ma_hours_closed ]); // 正确应该是 array_push($results, [ 'hours_open' => $data[$i]['hours_open'], 'hours_closed' => $data[$i]['hours_closed'], 'ma_hours_closed' => $ma_hours_closed ]); - 索引边界错误:你当前的判断是
if ($i < 5)时设0,但移动平均周期是6,意味着第7条记录(对应索引i=6)才应该计算前6条的平均值。当i=5时进入else分支,$c = $i-6会得到-1,这时候访问$results[$c]会触发Undefined offset错误,因为$results此时只有0-4这5个元素。正确的判断应该是if ($i < 6),这样前6条记录(i=0到5)的移动平均设为0,从i=6开始计算有效平均。
实现逻辑的合理性
如果修正了上面的两个问题,你的代码逻辑是正确的:它确实能计算出周期为6的滑动平均——从第7条开始,每次取前6条的hours_closed值求平均。但从效率角度看,这种实现有优化空间:
- 你当前的方式是每次计算平均时都循环6次求和,当数据量很大(比如上万条记录)时,时间复杂度是
O(n*6),会有不必要的性能开销。 - 更高效的方式是用滑动窗口求和:维护一个当前窗口的总和,每新增一条记录时,减去窗口最左侧的旧值,加上当前的新值,再除以6得到平均。这样时间复杂度降到
O(n),性能提升明显。
优化后的代码示例
$data = $r['Data']; $results = []; $windowSum = 0; $windowSize = 6; for ($i = 0; $i < count($data); $i++) { $currentClosed = $data[$i]['hours_closed']; $windowSum += $currentClosed; if ($i < $windowSize - 1) { // 前6条记录(i=0到5),移动平均设为0 $ma_hours_closed = 0; } else { // 从第7条开始,计算窗口平均 $ma_hours_closed = $windowSum / $windowSize; // 移除窗口最左侧的旧值,为下一次循环做准备 $windowSum -= $results[$i - $windowSize]['hours_closed']; } array_push($results, [ 'hours_open' => $data[$i]['hours_open'], 'hours_closed' => $currentClosed, 'ma_hours_closed' => $ma_hours_closed ]); }
总结
你的原始实现逻辑方向是对的,但存在索引和键名的小错误;修正后可以正常工作,但在数据量大时效率偏低。如果你的数据量不大,原始实现(修正错误后)完全够用;如果数据量较大,建议用滑动窗口的方式优化。
内容的提问来源于stack exchange,提问作者dexter
相关产品推荐
相关产品推荐

