单列表中的对

Apa*_*ala 87 python zip idioms list slice

通常情况下,我发现需要成对处理列表.我想知道哪个是pythonic和有效的方法,并在谷歌上找到了这个:

pairs = zip(t[::2], t[1::2])
Run Code Online (Sandbox Code Playgroud)

我认为这是pythonic足够的,但在最近讨论成语与效率之后,我决定做一些测试:

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
Run Code Online (Sandbox Code Playgroud)

这些是我的电脑上的结果:

1.48668909073 2.63187503815 1.14518594742
0.105381965637 1.35109519958 1.24571323395
0.00257992744446 1.46182489395 1.45924496651
0.00251388549805 1.70076990128 1.69825601578
Run Code Online (Sandbox Code Playgroud)

如果我正确地解释它们,那应该意味着在Python中实现列表,列表索引和列表切片非常有效.这是令人安慰和意外的结果.

还有另一种"更好"的方式来成对遍历列表吗?

请注意,如果列表具有奇数个元素,则最后一个元素将不在任何对中.

哪种方法可以确保包含所有元素?

我从测试的答案中添加了这两个建议:

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

def chunkwise(t, size=2):
    it = iter(t)
    return izip(*[it]*size)
Run Code Online (Sandbox Code Playgroud)

这些是结果:

0.00159502029419 1.25745987892 1.25586485863
0.00222492218018 1.23795199394 1.23572707176
Run Code Online (Sandbox Code Playgroud)

结果到目前为止

大多数pythonic和非常有效:

pairs = izip(t[::2], t[1::2])
Run Code Online (Sandbox Code Playgroud)

最有效和非常pythonic:

pairs = izip(*[iter(t)]*2)
Run Code Online (Sandbox Code Playgroud)

我花了一点时间才知道第一个答案使用了两个迭代器,而第二个答案使用了一个迭代器.

为了处理具有奇数个元素的序列,建议增加原始序列,添加一个None与前一个最后一个元素配对的元素(),这是可以实现的itertools.izip_longest().

最后

请注意,在Python 3.x中,zip()表现为itertools.izip(),并且itertools.izip() 已经消失.

Joc*_*zel 43

我最喜欢的方式:

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)
Run Code Online (Sandbox Code Playgroud)

如果要对所有元素进行配对,显然可能需要填充值:

from itertools import izip_longest
def blockwise(t, size=2, fillvalue=None):
    it = iter(t)
    return izip_longest(*[it]*size, fillvalue=fillvalue)
Run Code Online (Sandbox Code Playgroud)


Tim*_*ker 37

我会说你的初始解决方案pairs = zip(t[::2], t[1::2])是最好的解决方案,因为它最容易阅读(在Python 3中,zip自动返回迭代器而不是列表).

为了确保包含所有元素,您可以简单地扩展列表None.

然后,如果列表具有奇数个元素,则最后一对将是(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)]
Run Code Online (Sandbox Code Playgroud)


Tom*_*ndt 6

我从小免责声明开始 - 不要使用下面的代码.它根本不是Pythonic,我写的只是为了好玩.它与@ THC4k pairwise功能类似,但它使用iterlambda关闭.它不使用itertools模块,不支持fillvalue.我把它放在这里因为有人可能会觉得它很有趣:

pairwise = lambda t: iter((lambda f: lambda: (f(), f()))(iter(t).next), None)
Run Code Online (Sandbox Code Playgroud)