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)