### Question :

Often enough, I’ve found the need to process a list by pairs. I was wondering which would be the pythonic and efficient way to do it, and found this on Google:

```
pairs = zip(t[::2], t[1::2])
```

I thought that was pythonic enough, but after a recent discussion involving idioms versus efficiency, I decided to do some tests:

```
import time
from itertools import islice, izip
def pairs_1(t):
return zip(t[::2], t[1::2])
def pairs_2(t):
return izip(t[::2], t[1::2])
def pairs_3(t):
return izip(islice(t,None,None,2), islice(t,1,None,2))
A = range(10000)
B = xrange(len(A))
def pairs_4(t):
# ignore value of t!
t = B
return izip(islice(t,None,None,2), islice(t,1,None,2))
for f in pairs_1, pairs_2, pairs_3, pairs_4:
# time the pairing
s = time.time()
for i in range(1000):
p = f(A)
t1 = time.time() - s
# time using the pairs
s = time.time()
for i in range(1000):
p = f(A)
for a, b in p:
pass
t2 = time.time() - s
print t1, t2, t2-t1
```

These were the results on my computer:

```
1.48668909073 2.63187503815 1.14518594742
0.105381965637 1.35109519958 1.24571323395
0.00257992744446 1.46182489395 1.45924496651
0.00251388549805 1.70076990128 1.69825601578
```

If I’m interpreting them correctly, that should mean that the implementation of lists, list indexing, and list slicing in Python is very efficient. It’s a result both comforting and unexpected.

**Is there another, “better” way of traversing a list in pairs?**

Note that if the list has an odd number of elements then the last one will not be in any of the pairs.

**Which would be the right way to ensure that all elements are included?**

I added these two suggestions from the answers to the tests:

```
def pairwise(t):
it = iter(t)
return izip(it, it)
def chunkwise(t, size=2):
it = iter(t)
return izip(*[it]*size)
```

These are the results:

```
0.00159502029419 1.25745987892 1.25586485863
0.00222492218018 1.23795199394 1.23572707176
```

## Results so far

Most pythonic and very efficient:

```
pairs = izip(t[::2], t[1::2])
```

Most efficient and very pythonic:

```
pairs = izip(*[iter(t)]*2)
```

It took me a moment to grok that the first answer uses two iterators while the second uses a single one.

To deal with sequences with an odd number of elements, the suggestion has been to augment the original sequence adding one element (`None`

) that gets paired with the previous last element, something that can be achieved with `itertools.izip_longest()`

.

## Finally

Note that, in Python 3.x, `zip()`

behaves as `itertools.izip()`

, and `itertools.izip()`

is gone.

##
Answer #1:

My favorite way to do it:

```
from itertools import izip
def pairwise(t):
it = iter(t)
return izip(it,it)
# for "pairs" of any length
def chunkwise(t, size=2):
it = iter(t)
return izip(*[it]*size)
```

When you want to pair all elements you obviously might need a fillvalue:

```
from itertools import izip_longest
def blockwise(t, size=2, fillvalue=None):
it = iter(t)
return izip_longest(*[it]*size, fillvalue=fillvalue)
```

##
Answer #2:

I’d say that your initial solution `pairs = zip(t[::2], t[1::2])`

is the best one because it is easiest to read (and in Python 3, `zip`

automatically returns an iterator instead of a list).

To ensure that all elements are included, you could simply extend the list by `None`

.

Then, if the list has an odd number of elements, the last pair will be `(item, None)`

.

```
>>> t = [1,2,3,4,5]
>>> t.append(None)
>>> zip(t[::2], t[1::2])
[(1, 2), (3, 4), (5, None)]
>>> t = [1,2,3,4,5,6]
>>> t.append(None)
>>> zip(t[::2], t[1::2])
[(1, 2), (3, 4), (5, 6)]
```

##
Answer #3:

I start with small disclaimer – don’t use the code below. It’s not Pythonic at all, I wrote just for fun. It’s similar to @THC4k `pairwise`

function but it uses `iter`

and `lambda`

closures. It doesn’t use `itertools`

module and doesn’t support `fillvalue`

. I put it here because someone might find it interesting:

```
pairwise = lambda t: iter((lambda f: lambda: (f(), f()))(iter(t).next), None)
```

##
Answer #4:

As far as most pythonic goes, I’d say the recipes supplied in the python source docs (some of which look a lot like the answers that @JochenRitzel provided) is probably your best bet ðŸ˜‰

```
def grouper(iterable, n, fillvalue=None):
"Collect data into fixed-length chunks or blocks"
# grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
```

On modern python you just have to use `zip_longest(*args, fillvalue=fillvalue)`

according to the corresponding doc page.

##
Answer #5:

Is there another, “better” way of traversing a list in pairs?

I can’t say for sure but I doubt it: Any other traversal would include more Python code which has to be interpreted. The built-in functions like zip() are written in C which is much faster.

Which would be the right way to ensure that all elements are included?

Check the length of the list and if it’s odd (`len(list) & 1 == 1`

), copy the list and append an item.

##
Answer #6:

```
>>> my_list = [1,2,3,4,5,6,7,8,9,10]
>>> my_pairs = list()
>>> while(my_list):
... a = my_list.pop(0); b = my_list.pop(0)
... my_pairs.append((a,b))
...
>>> print(my_pairs)
[(1, 2), (3, 4), (5, 6), (7, 8), (9, 10)]
```

##
Answer #7:

Only do it:

```
>>> l = [1, 2, 3, 4, 5, 6]
>>> [(x,y) for x,y in zip(l[:-1], l[1:])]
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
```

##
Answer #8:

Here is an example of creating pairs/legs by using a generator. Generators are free from stack limits

```
def pairwise(data):
zip(data[::2], data[1::2])
```

Example:

```
print(list(pairwise(range(10))))
```

Output:

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