从单一列表中的成对组合

4 浏览
0 Comments

从单一列表中的成对组合

此问题已经有答案:
如何将列表分成相等的块?

社区已在 8 个月前对是否重新开放此问题进行了审核,并将其关闭:

原关闭原因未被解决

我经常需要对列表进行成对处理。我想知道什么是 Pythonic 和高效的方法,在 Google 上找到了这个:

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

我认为这已经很 Pythonic,但在最近涉及成语语法 versus 效率的讨论中,我决定进行一些测试:

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

目前为止的结果

最pythonic和非常高效:

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

最高效和非常pythonic:

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

我需要一点时间去理解第一个答案使用了两个迭代器,而第二个答案使用了一个迭代器。

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

最后

请注意,在Python 3.x中,zip()的行为类似于itertools.izip(),而itertools.izip()已被删除。

admin 更改状态以发布 2023年5月25日
0
0 Comments

我认为你最初的解决方案 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)]

0
0 Comments

我最喜欢的做法是:

def pairwise(t):
    it = iter(t)
    return zip(it,it)
# for "pairs" of any length
def chunkwise(t, size=2):
    it = iter(t)
    return zip(*[it]*size)

当你想要匹配所有元素时,显然可能需要一个填充值:

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

使用Python 3, itertools.izip 现在变成了 zip .. 要使用旧版本的Python,请使用

from itertools import izip as zip

0