Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
285 views
in Technique[技术] by (71.8m points)

python - 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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This is precisely what the pairwise itertools recipe is for, for n=2 that is.

from itertools import tee

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return zip(a, b)

Demo:

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

If you are looking for variable group sizes, see user2357112's answer (I like the approach), or more generally you can implement a sliding window iterator and take slices of which there are many approaches.


As an aside, a possibly poorly performing but amusing one-line window you could slice (to control the overlap) that isn't on the linked question would be this, using the new yield from syntax to combine generators.

from itertools import tee, islice
def roll_window(it, sz):
    yield from zip(*[islice(it, g, None) for g, it in enumerate(tee(it, sz))])

Demo:

>>> b = [1.0,1.5,2.0,2.5,3.0, 3.5, 4.0, 4.5]
>>> list(islice(window(b, 3), None, None, 2))
[(1.0, 1.5, 2.0), (2.0, 2.5, 3.0), (3.0, 3.5, 4.0)]

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...