Skip to content
Reliable Data Engineering
Practice problem medium sliding-windowdequedesign
Solve it in the browser (Python editor)

Moving Average from a Data Stream

Difficulty: Medium · Topics: sliding-window, deque, design · Asked at: Google, Two Sigma, Robinhood

Problem

Implement MovingAverage(size) with next(value) -> float returning the average of the last size values (or of all values if fewer). Each call must be O(1).

Starter code

class MovingAverage:
    def __init__(self, size: int):
        pass

    def next(self, value: float) -> float:
        pass

Hints

Hint 1

A deque plus a running sum: add the new value, subtract the evicted one.

Solution

from collections import deque

class MovingAverage:
    def __init__(self, size: int):
        if size <= 0:
            raise ValueError("size must be positive")
        self.size = size
        self.window = deque()
        self.total = 0.0

    def next(self, value: float) -> float:
        self.window.append(value)
        self.total += value
        if len(self.window) > self.size:
            self.total -= self.window.popleft()
        return self.total / len(self.window)

Tests

Your solution should pass these:

m = MovingAverage(3)
assert m.next(1) == 1.0
assert m.next(10) == 5.5
assert abs(m.next(3) - 14 / 3) < 1e-9
assert m.next(5) == 6.0
try:
    MovingAverage(0)
    assert False, "should raise"
except ValueError:
    pass

Explanation

O(1) time per value and O(size) memory. With floats, a long-running sum accumulates rounding error. Mention periodic recomputation or math.fsum/Kahan summation for long-lived streams. A time-based window (last 5 minutes) uses the same deque but evicts by timestamp instead of count.