我有时需要在 Python 中迭代一个列表,查看“当前”元素和“下一个”元素。到目前为止,我已经使用如下代码完成了此操作:
for current, next in zip(the_list, the_list[1:]): # Do something
这有效并且符合我的期望,但是有没有更惯用或更有效的方法来做同样的事情?
这是来自itertools模块文档的相关示例:
import itertools def pairwise(iterable): "s -> (s0, s1), (s1, s2), (s2, s3), ..." a, b = itertools.tee(iterable) next(b, None) return zip(a, b)
对于 Python 2,您需要itertools.izip代替zip:
itertools.izip
zip
import itertools def pairwise(iterable): "s -> (s0, s1), (s1, s2), (s2, s3), ..." a, b = itertools.tee(iterable) next(b, None) return itertools.izip(a, b)
这是如何工作的:
首先,创建了两个并行迭代器a和b(tee()调用),它们都指向原始可迭代对象的第一个元素。第二个迭代器b向前移动了 1 步(next(b, None)调用)。此时指向as0又b指向s1。两者a和b都可以独立地遍历原始迭代器 - izip 函数采用两个迭代器并生成成对的返回元素,以相同的速度推进两个迭代器。
a
b
tee()
next(b, None)
一个警告:该tee()函数产生两个迭代器,它们可以相互独立地前进,但它是有代价的。如果其中一个迭代器比另一个更进一步,则tee() 需要将消耗的元素保留在内存中,直到第二个迭代器也使用它们(它不能“倒回”原始迭代器)。在这里没关系,因为一个迭代器只比另一个迭代器领先 1 步,但通常这种方式很容易使用大量内存。
并且由于tee()可以带一个n参数,这也可以用于两个以上的并行迭代器:
n
def threes(iterator): "s -> (s0, s1, s2), (s1, s2, s3), (s2, s3, 4), ..." a, b, c = itertools.tee(iterator, 3) next(b, None) next(c, None) next(c, None) return zip(a, b, c)