Iterate over all pairs of consecutive items in a list

Given a list

l = [1, 7, 3, 5]

I want to iterate over all pairs of consecutive list items (1,7), (7,3), (3,5), i.e.

for i in xrange(len(l) - 1):
    x = l[i]
    y = l[i + 1]
    # do something

I would like to do this in a more compact way, like

for x, y in someiterator(l): ...

Is there a way to do do this using builtin Python iterators? I’m sure the itertools module should have a solution, but I just can’t figure it out.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

Just use zip

>>> l = [1, 7, 3, 5]
>>> for first, second in zip(l, l[1:]):
...     print first, second
...
1 7
7 3
3 5

If you use Python 2 (not suggested) you might consider using the izip function in itertools for very long lists where you don’t want to create a new list.

import itertools

for first, second in itertools.izip(l, l[1:]):
    ...

Method 2

Look at pairwise at itertools recipes: http://docs.python.org/2/library/itertools.html#recipes

Quoting from there:

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

A General Version

A general version, that yields tuples of any given positive natural size, may look like that:

def nwise(iterable, n=2):                                                      
    iters = tee(iterable, n)                                                     
    for i, it in enumerate(iters):                                               
        next(islice(it, i, i), None)                                               
    return izip(*iters)

Method 3

I would create a generic grouper generator, like this

def grouper(input_list, n = 2):
    for i in xrange(len(input_list) - (n - 1)):
        yield input_list[i:i+n]

Sample run 1

for first, second in grouper([1, 7, 3, 5, 6, 8], 2):
    print first, second

Output

1 7
7 3
3 5
5 6
6 8

Sample run 1

for first, second, third in grouper([1, 7, 3, 5, 6, 8], 3):
    print first, second, third

Output

1 7 3
7 3 5
3 5 6
5 6 8

Method 4

Generalizing sberry’s approach to nwise with comprehension:

def nwise(lst, k=2):
    return list(zip(*[lst[i:] for i in range(k)]))

Eg

nwise(list(range(10)),3)

[(0, 1, 2), (1, 2, 3), (2, 3, 4), (3, 4, 5), (4, 5, 6), (5, 6,
7), (6, 7, 8), (7, 8, 9)]

Method 5

A simple means to do this without unnecessary copying is a generator that stores the previous element.

def pairs(iterable):
    """Yield elements pairwise from iterable as (i0, i1), (i1, i2), ..."""
    it = iter(iterable)
    try:
        prev = next(it)
    except StopIteration:
        return
    for item in it:
        yield prev, item
        prev = item

Unlike index-based solutions, this works on any iterable, including those for which indexing is not supported (e.g. generator) or slow (e.g. collections.deque).

Method 6

You could use a zip.

>>> list(zip(range(5), range(2, 6)))
[(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)]

Just like a zipper, it creates pairs. So, to to mix your two lists, you get:

>>> l = [1,7,3,5]
>>> list(zip(l[:-1], l[1:]))
[(1, 7), (7, 3), (3, 5)]

Then iterating goes like

for x, y in zip(l[:-1], l[1:]):
    pass

Method 7

If you wanted something inline but not terribly readable here’s another solution that makes use of generators. I expect it’s also not the best performance wise :-/

Convert list into generator with a tweak to end before the last item:

gen = (x for x in l[:-1])

Convert it into pairs:

[(gen.next(), x) for x in l[1:]]

That’s all you need.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x