Pares de una sola lista

A menudo, he encontrado la necesidad de procesar una lista por pares. Me preguntaba cuál sería la forma pitónica y eficiente de hacerlo, y encontré esto en Google:

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

Pensé que eso era bastante pitónico, pero después de una discusión reciente sobremodismos versus eficiencia, Decidí hacer algunas pruebas:

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

Estos fueron los resultados en mi computadora:

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

Si los estoy interpretando correctamente, eso debería significar que la implementación de listas, indexación de listas y corte de listas en Python es muy eficiente. Es un resultado reconfortante e inesperado.

¿Hay otra forma "mejor" de recorrer una lista en pares?

Tenga en cuenta que si la lista tiene un número impar de elementos, el último no estará en ninguno de los pares.

¿Cuál sería la forma correcta de garantizar que se incluyan todos los elementos?

Agregué estas dos sugerencias de las respuestas a las pruebas:

def pairwise(t):
    it = iter(t)
    return izip(it, it)

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

Estos son los resultados:

0.00159502029419 1.25745987892 1.25586485863
0.00222492218018 1.23795199394 1.23572707176
Resultados hasta ahora

Más pitónico y muy eficiente:

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

Más eficiente y muy pitónico:

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

Me tomó un momento entender que la primera respuesta usa dos iteradores mientras que la segunda usa uno solo.

Para lidiar con secuencias con un número impar de elementos, la sugerencia ha sido aumentar la secuencia original agregando un elemento (None) que se empareja con el último elemento anterior, algo que se puede lograr conitertools.izip_longest().

Finalmente

Tenga en cuenta que, en Python 3.x,zip() se comporta comoitertools.izip()yitertools.izip() se ha ido.

Respuestas a la pregunta(6)

Su respuesta a la pregunta