Welcome to Day 46 of the #80DaysOfChallenges journey! This intermediate challenge implements a Simple Moving Average (SMA) calculator using an efficient sliding window approach that maintains a running sum, achieving O(n) time complexity while avoiding redundant calculations. It handles user-provided data series and window size, returning a list of averages with proper validation, making it a practical tool for time-series smoothing, financial indicators, or signal processing. If you're advancing from basic loops to performance-aware algorithms or dealing with sequential data, this "Python moving average" script demonstrates a function that's optimized, easy to understand, and ready for extensions like exponential or weighted averages.
💡 Key Takeaways from Day 46: Moving Average Function
This task features a function that initializes the first window sum and slides forward with constant-time updates, plus simple input validation. It's a textbook sliding window optimization: stateful sum reduces work from O(nk) to O(n). We'll detail: function with validation and initial sum, sliding loop with incremental updates, and main with input parsing.
1. Function Design: Validation and First Window Setup
The calculate_moving_average function validates and computes the first average:
def calculate_moving_average(data: list[int], window_size: int) -> list[float]:
"""
Calculate simple moving average (SMA) for a given data list and window size.
Returns a list of floats representing the SMA values.
"""
if window_size <= 0 or window_size > len(data):
return [] # invalid window, return empty list
moving_averages = []
window_sum = sum(data[:window_size]) # initial sum for the first window
moving_averages.append(window_sum / window_size)
Early return on invalid window prevents errors. Initial sum uses slice for clarity (O(k)), then appends first average. This prepares the running sum for efficient sliding.
2. Sliding Loop: Constant-Time Sum Updates
The core loop advances the window:
# Slide the window across the data
for i in range(window_size, len(data)):
window_sum = window_sum - data[i - window_size] + data[i]
moving_averages.append(window_sum / window_size)
return moving_averages
Subtracts the outgoing element, adds the incoming, recomputes average in O(1) per step. Total O(n), elegant for large datasets. For data [1,2,3,4,5], window=3: averages [2.0, 3.0, 4.0].
3. Main Interactive: Data and Window Input
Script reads inputs and calls:
input_data = list(map(int, input("Enter the data series (space-separated): ").split()))
window_size = int(input("Enter the window size: "))
result = calculate_moving_average(input_data, window_size)
print("Moving Average:", result)
Parses space-separated ints, prompts window, prints list. Assumes valid input (could add try for robustness).
🎯 Summary and Reflections
This moving average calculator highlights incremental updates for efficiency. It reinforced:
- Running state: Window sum turns quadratic into linear.
- Window pattern: Fundamental for many sequence problems.
- Practical focus: Smoothing real data like prices or sensors.
Reflections: Simple yet powerful, output length = len(data) - window + 1. For circular windows, wrap data.
Advanced Alternatives: Deque for general window stats. Numpy.cumsum trick: (cum[window:] - cum[:-window]) / window. Your average variant? Share!
🚀 Next Steps and Resources
Day 46 optimized sequences, prepping for data streams. In #80DaysOfChallenges? Added EMA? Post!
- Source Code for Challenge #46: scripts/moving_average.py
- Main Repository: 80-days-of-challenges
- Daily Updates: Twitter/X (@Shahrouzlogs)
Top comments (0)