title: Pairs from single list
body: <p>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:</p>
  
  <pre><code>pairs = zip(t[::2], t[1::2])
  </code></pre>
  
  <p>I thought that was pythonic enough, but after a recent discussion involving <a href="https://stackoverflow.com/questions/4619367/avoid-object-aliasing-in-python/4619575#4619575">idioms versus efficiency</a>, I decided to do some tests:</p>
  
  <pre><code>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
  </code></pre>
  
  <p>These were the results on my computer:</p>
  
  <pre><code>1.48668909073 2.63187503815 1.14518594742
  0.105381965637 1.35109519958 1.24571323395
  0.00257992744446 1.46182489395 1.45924496651
  0.00251388549805 1.70076990128 1.69825601578
  </code></pre>
  
  <p>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.</p>
  
  <p><strong>Is there another, "better" way of traversing a list in pairs?</strong></p>
  
  <p>Note that if the list has an odd number of elements then the last one will not be in any of the pairs. </p>
  
  <p><strong>Which would be the right way to ensure that all elements are included?</strong></p>
  
  <p>I added these two suggestions from the answers to the tests:</p>
  
  <pre><code>def pairwise(t):
      it = iter(t)
      return izip(it, it)
  
  def chunkwise(t, size=2):
      it = iter(t)
      return izip(*[it]*size)
  </code></pre>
  
  <p>These are the results:  </p>
  
  <pre><code>0.00159502029419 1.25745987892 1.25586485863
  0.00222492218018 1.23795199394 1.23572707176
  </code></pre>
  
  <h2>Results so far</h2>
  
  <p>Most pythonic and very efficient:</p>
  
  <pre><code>pairs = izip(t[::2], t[1::2])
  </code></pre>
  
  <p>Most efficient and very pythonic:</p>
  
  <pre><code>pairs = izip(*[iter(t)]*2)
  </code></pre>
  
  <p>It took me a moment to grok that the first answer uses two iterators while the second uses a single one.</p>
  
  <p>To deal with sequences with an odd number of elements, the suggestion has been to augment the original sequence adding one element (<code>None</code>) that gets paired with the previous last element, something that can be achieved with <code>itertools.izip_longest()</code>.</p>
  
  <h2>Finally</h2>
  
  <p>Note that, in Python 3.x, <code>zip()</code> behaves as <code>itertools.izip()</code>, and <code>itertools.izip()</code>  is gone.</p>