Пары из одного списка

Достаточно часто , Я обнаружил необходимость обрабатывать список по парам. Мне было интересно, какой питонический и эффективный способ сделать это, и я нашел это в Google:

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

Я думал, что это достаточно питонический, но после недавнего обсуждения идиом против эффективности я решил проделайте несколько тестов:

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

Вот результаты на моем компьютере:

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

Если я интерпретирую их правильно, это должно означать, что реализация списков, индексации списков и нарезки списков в Python очень эффективна. Это' результат как успокаивающий, так и неожиданный.

Есть ли другой, «лучший» способ обхода списка в парах?

Обратите внимание, что если список имеет нечетное количество элементов, то последний из них не будет ни в одном из пары.

Что было бы правильным способом гарантировать включение всех элементов?

Я добавил эти два предложения из ответов на тесты:

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

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

Вот результаты:

0.00159502029419 1.25745987892 1.25586485863
0.00222492218018 1.23795199394 1.23572707176

На данный момент результаты

Большинство питонический и очень эффективный:

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

Наиболее эффективный и очень питонический:

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

Мне потребовалось мгновение, чтобы понять, что в первом ответе используются два итератора, а во втором - один.

Для работы с последовательностями с нечетным числом элементов, было предложено увеличить исходную последовательность, добавив один элемент ( None ), который будет соединен с предыдущим последним элементом, то, что может быть достигнуто с помощью itertools.izip_longest () .

Наконец

Обратите внимание, что в Python 3.x zip () ведет себя как itertools. izip () и itertools.izip () исчезли.

86
задан Community 23 May 2017 в 12:10
поделиться