Pairs from the same list.

Quite often, I found the need to process a list in pairs. I was wondering what would be a pythonic and effective way to do this, and found this on Google:

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

I thought it was pythonic enough, but after a recent discussion of idioms against 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 interpret them correctly, this should mean that implementing lists, indexing lists, and splitting lists in Python is very effective. This result is both comforting and unexpected.

Is there any other β€œbest” way to move a list in pairs?

Please note that if the list has an odd number of elements, the latter will not be in any of the pairs.

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

I added these two sentences 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) 

Here are the results:

 0.00159502029419 1.25745987892 1.25586485863 0.00222492218018 1.23795199394 1.23572707176 

Results so far

Most pythonic and very effective:

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

Most effective and very pythonic:

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

It took me a while to figure out that the first answer uses two iterators, and the second uses one.

To deal with sequences with an odd number of elements, it was proposed to increase the original sequence by adding one element ( None ), which connects to the previous last element, which can be achieved using itertools.izip_longest() .

Finally

Note that in Python 3.x, zip() behaves like itertools.izip() , and itertools.izip() missing.

+77
python list idioms slice zip
Jan 07 '11 at 17:20
source share
6 answers

My favorite way to do this is:

 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) 

If you want to join all the elements, you obviously might need a fillvalue value:

 from itertools import izip_longest def blockwise(t, size=2, fillvalue=None): it = iter(t) return izip_longest(*[it]*size, fillvalue=fillvalue) 
+38
Jan 07 '11 at 17:35
source share

I would say that your initial solution pairs = zip(t[::2], t[1::2]) is the best because it is easiest to read (and in Python 3, zip automatically returns an iterator instead of a list).

To ensure that all items are included, you can simply expand the list to 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)] 
+32
Jan 07 2018-11-11T00:
source share

I start with a small disclaimer - do not use the code below. This is not Pythonic at all, I wrote just for fun. It is similar to @ THC4k pairwise pairwise , but uses iter and lambda closure. It does not use the itertools module and does not support fillvalue . I put it here because it might seem interesting to someone:

 pairwise = lambda t: iter((lambda f: lambda: (f(), f()))(iter(t).next), None) 
+6
Jan 08 2018-11-11T00:
source share

For most pythonic, I would say the recipes provided in the python source documents (some of them very similar to the answers provided by @JochenRitzel) are 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) 
+3
May 04 '15 at 8:24
source share

Is there any other β€œbetter” way to move a list in pairs?

I can’t say for sure, but I doubt it: any other workaround will include more Python code that needs to be interpreted. Built-in functions like zip () are written in C, which is much faster.

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

Check the length of the list, and if it is odd ( len(list) & 1 == 1 ), copy the list and add an item.

+2
Jan 07 2018-11-11T00:
source share
 >>> 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)] 
0
Feb 19 '19 at 10:39
source share



All Articles