DEV Community

Shahrouz Nikseresht
Shahrouz Nikseresht

Posted on

Day 46: Python Moving Average Calculator, Optimized Sliding Window for Simple Moving Average Computation

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)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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!

Top comments (0)