Search code examples
pythonlist-comprehensionpython-itertools

Cyclical Sliding Window Iteration


Consider some given sequence and a window length, say the list

a = [13 * i + 1 for i in range(24)]

(so that

In [61]: a
Out[61]: 
[1,
 14,
 27,
 40,
 ...,
 287,
 300]

)

and window length 3.

I'd like to take the sliding window sum of this sequence, but cyclically; i.e., to calculate the length-24 list:

[sum([1, 14, 27]),
 sum([14, 27, 40]),
 ...,
 sum([287, 300, 1]),
 sum([300, 1, 14])]

The best I could come up with, using collections.deque and Stupid Lambda Tricks, was

d = collections.deque(range(24))
d.rotate(1)
map(lambda _: d.rotate(-1) or sum(a[i] for i in list(d)[: 3]), range(24))

Is there something less horrible?


Solution

  • What about the simple

    a = [13 * i + 1 for i in range(24)]
    w = 3
    
    aa = a + a[:w]
    print([sum(aa[i:i+w]) for i in range(len(a))])
    

    Note that if the window is big there are better ways to compute a sliding window sum in O(n) (i.e. with a constant time per element, independently of the size of the window).

    The idea is to do a "scan conversion" replacing each element with the sum of all elements from the start (this requires single pass).

    After that the sum of elements from x0 to x1 is then computed in O(1) with

    sum_table[x1] - sum_table[x0]
    

    In code:

    sum_table = [0]
    for v in a:
        sum_table.append(sum_table[-1] + v)
    for v in a[:w]:
        sum_table.append(sum_table[-1] + v)
    print([sum_table[i+w] - sum_table[i] for i in range(len(a))])