cpicanco cpicanco - 6 months ago 19
Python Question

Iterate over n successive elements of list (with overlapping)

The itertools python module implements some basic building blocks for iterators. As they say, "they form an iterator algebra". I was expecting, but I could not find a succinctly way of doing the following iteration using the module. Given a list of ordered real numbers, for example

a = [1.0,1.5,2.0,2.5,3.0]

... return a new list (or just iterate) grouping by some
value, say

b = [(1.0,1.5),(1.5,2.0),(2.0,2.5),(2.5,3.0)]

The way I found of doing this was as follows. First split the list in two, with evens and odds indexes:

even, odds = a[::2], a[1::2]

Then construct the new list:

b = [(even, odd) for even, odd in zip(evens, odds)]
b = sorted(b + [(odd, even) for even, odd in zip(evens[1:], odds)])

In essence, it is similar to a moving mean.

Is there a succinctly way of doing this (with or without itertools)?


For 2, you can just do

b = zip(a, a[1:])  # or list(zip(...)) on Python 3 if you really want a list

For fixed n, the technique is similar:

# n = 4
b = zip(a, a[1:], a[2:], a[3:])

For variable n, you could zip a variable number of slices, or (especially if the window size is close to the size of a) you could use slicing to take windows directly:

b = zip(*[a[i:] for i in xrange(n)])
# or
b = [tuple(a[i:i+n]) for i in xrange(len(a)-n)]

If a is not a list, you could generalize the pairwise recipe from the itertools docs:

import copy
import itertools

def nwise(iterable, n):
    # Make n tees at successive positions along the iterable.
    tees = list(itertools.tee(iterable, 1))
    for _ in xrange(n-1):

    return zip(*tees)