为了账号安全,请及时绑定邮箱和手机立即绑定

一对单对。

/ 猿问

一对单对。

偶然的你 2019-12-26 10:09:06

通常,我发现需要成对处理列表。我想知道哪种方法是有效的pythonic方法,并在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

到目前为止的结果

最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() 消失了。


查看完整描述

3 回答

?
喵喔喔

我最喜欢的方式:


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)

当您想配对所有元素时,您显然可能需要一个fillvalue:


from itertools import izip_longest

def blockwise(t, size=2, fillvalue=None):

    it = iter(t)

    return izip_longest(*[it]*size, fillvalue=fillvalue)


查看完整回答
反对 2019-12-26
?
守着一只汪

我想说您的初始解决方案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)]


查看完整回答
反对 2019-12-26
?
慕斯卡3215842

我从小的免责声明开始-不要使用下面的代码。根本不是Pythonic,我只是为了好玩而写。它类似于@ THC4k pairwise函数,但使用iter和lambda闭包。它不使用itertools模块,不支持fillvalue。我把它放在这里是因为有人可能会觉得有趣:


pairwise = lambda t: iter((lambda f: lambda: (f(), f()))(iter(t).next), None)


查看完整回答
反对 2019-12-26

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信