Calculate a bounded moving average from a short list
Calculate a bounded moving average from a short list
To calculate a bounded moving average for [2, 4, 8, 10] with window size 3, append values to deque(maxlen=3) and emit an average only when the deque is full. The resulting full-window averages are 4.6667 for [2, 4, 8] and 7.3333 for [4, 8, 10].
The failure function shows the boundary error directly. It slices from the start through endpoints 1, 2, 3, and 4, producing 2.0, 3.0, 4.6667, and 6.0. The first two results are partial windows, so they do not satisfy a three-item moving-average contract. The final 6.0 is also an average of all four values rather than the final three-item window.
The correction maintains a bounded deque. Before it contains three elements, the loop deliberately emits nothing. Once full, statistics.fmean() calculates the current window’s floating-point mean. The formatting step makes the transcript consistently show four decimal places, while the assertions compare rounded values and confirm the original list was not changed.
collections.deque is a standard-library double-ended queue; maxlen makes its retained length bounded. statistics.fmean() was added in Python 3.8, so this exact example requires Python 3.8 or later. The calculation is an unweighted arithmetic mean; it does not address missing data, timestamps, or numerical policies beyond this small fixture. Python deque documentation and Python statistics.fmean() documentation provide the API details.
AI assistance disclosure: This article was prepared with AI assistance and checked with the synthetic assertions shown below.
from collections import deque
from statistics import fmean
values = [2, 4, 8, 10]
window_size = 3
def partial_averages(items):
return [sum(items[:end]) / len(items[:end]) for end in range(1, len(items) + 1)]
def full_window_averages(items, size):
window = deque(maxlen=size)
averages = []
for value in items:
window.append(value)
if len(window) == size:
averages.append(fmean(window))
return averages
partial = partial_averages(values)
full = full_window_averages(values, window_size)
partial_display = [round(value, 4) for value in partial]
full_display = [round(value, 4) for value in full]
assert values == [2, 4, 8, 10]
assert partial_display == [2.0, 3.0, 4.6667, 6.0]
assert full_display == [4.6667, 7.3333]
print(f"input unchanged: {values}")
print(f"partial: {partial_display}")
print(f"full: {full_display}")
input unchanged: [2, 4, 8, 10]
partial: [2.0, 3.0, 4.6667, 6.0]
full: [4.6667, 7.3333]