[英]Pairs from single list
通常,我发现需要成对处理列表。 我想知道哪种 Pythonic 和有效的方法可以做到这一点,并在 Google 上找到了这个:
pairs = zip(t[::2], t[1::2])
我认为这已经足够 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
这些是我电脑上的结果:
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()
已消失。
我最喜欢的做法:
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)
当您想要配对所有元素时,您显然可能需要一个填充值:
from itertools import izip_longest
def blockwise(t, size=2, fillvalue=None):
it = iter(t)
return izip_longest(*[it]*size, fillvalue=fillvalue)
我会说你的初始解决方案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)]
我从小的免责声明开始 - 不要使用下面的代码。 它根本不是 Pythonic,我只是为了好玩而写的。 它类似于@THC4k pairwise
函数,但它使用iter
和lambda
闭包。 它不使用itertools
模块,也不支持fillvalue
。 我把它放在这里是因为有人可能会觉得它很有趣:
pairwise = lambda t: iter((lambda f: lambda: (f(), f()))(iter(t).next), None)
就大多数 pythonic 而言,我会说python 源文档中提供的食谱(其中一些看起来很像@JochenRitzel 提供的答案)可能是您最好的选择;)
def grouper(iterable, n, fillvalue=None):
"Collect data into fixed-length chunks or blocks"
# grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
在现代python上,您只需要根据相应的文档页面使用zip_longest(*args, fillvalue=fillvalue)
。
>>> my_list = [1,2,3,4,5,6,7,8,9,10]
>>> my_pairs = list()
>>> while(my_list):
... a = my_list.pop(0); b = my_list.pop(0)
... my_pairs.append((a,b))
...
>>> print(my_pairs)
[(1, 2), (3, 4), (5, 6), (7, 8), (9, 10)]
还有另一种“更好”的成对遍历列表的方法吗?
我不能肯定,但我对此表示怀疑:任何其他遍历都会包含更多必须解释的 Python 代码。 像 zip() 这样的内置函数是用 C 编写的,速度要快得多。
哪个是确保包含所有元素的正确方法?
检查列表的长度,如果它是奇数( len(list) & 1 == 1
),复制列表并附加一个项目。
只做:
>>> l = [1, 2, 3, 4, 5, 6]
>>> [(x,y) for x,y in zip(l[:-1], l[1:])]
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
这是使用生成器创建对/腿的示例。 生成器不受堆栈限制
def pairwise(data):
zip(data[::2], data[1::2])
示例:
print(list(pairwise(range(10))))
输出:
[(0, 1), (2, 3), (4, 5), (6, 7), (8, 9)]
以防万一有人需要算法方面的答案,这里是:
>>> def getPairs(list):
... out = []
... for i in range(len(list)-1):
... a = list.pop(0)
... for j in a:
... out.append([a, j])
... return b
>>>
>>> k = [1, 2, 3, 4]
>>> l = getPairs(k)
>>> l
[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
但请注意,您的原始列表也将缩减为其最后一个元素,因为您在其上使用了pop
。
>>> k
[4]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.