Skip to content
Advertisement

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 n value, say 2

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)?


PS.:

Application

Imagine the a list as the set of timestamps of some events occurred during an experiment:

timestamp       event
47.8            1a
60.5            1b
67.4            2a
74.5            2b
78.5            1a
82.2            1b
89.5            2a
95.3            2b
101.7           1a
110.2           1b
121.9           2a
127.1           2b

...

This code is being used to segment those events in accord with different temporal windows. Right now I am interested in the data between 2 successive events; ‘n > 2’ would be used only for exploratory purposes.

Advertisement

Answer

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+1)]

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):
        tees.append(copy.copy(tees[-1]))
        next(tees[-1])

    return zip(*tees)
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement