对列表中的所有连续项对进行迭代

给我一份名单

l = [1, 7, 3, 5]

我想迭代所有对连续的列表项 (1,7), (7,3), (3,5),即。

for i in xrange(len(l) - 1):
x = l[i]
y = l[i + 1]
# do something

我想用一种更简洁的方式,比如

for x, y in someiterator(l): ...

有没有一种方法可以使用内置的 Python 迭代器来实现这一点?我确信 itertools模块应该有一个解决方案,但我就是想不出来。

58121 次浏览

什么都没有

>>> l = [1, 7, 3, 5]
>>> for first, second in zip(l, l[1:]):
...     print first, second
...
1 7
7 3
3 5

如果您使用 Python2(不建议使用) ,您可以考虑使用 itertools中的 izip函数来处理不希望创建新列表的非常长的列表。

import itertools


for first, second in itertools.izip(l, l[1:]):
...

看看 pairwise的 itertools 菜谱: http://docs.python.org/2/library/itertools.html#recipes

引用如下:

def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return izip(a, b)

一般版本

一个通用的版本,产生任何给定的正自然大小的元组,可能看起来是这样的:

def nwise(iterable, n=2):
iters = tee(iterable, n)
for i, it in enumerate(iters):
next(islice(it, i, i), None)
return izip(*iters)

你可以用 zip

>>> list(zip(range(5), range(2, 6)))
[(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)]

就像拉链一样,它创建成对。所以,要混合你的两个列表,你可以得到:

>>> l = [1,7,3,5]
>>> list(zip(l[:-1], l[1:]))
[(1, 7), (7, 3), (3, 5)]

然后迭代就像

for x, y in zip(l[:-1], l[1:]):
pass

我会创建一个通用的 grouper生成器,像这样

def grouper(input_list, n = 2):
for i in xrange(len(input_list) - (n - 1)):
yield input_list[i:i+n]

样本运行1

for first, second in grouper([1, 7, 3, 5, 6, 8], 2):
print first, second

输出

1 7
7 3
3 5
5 6
6 8

样本运行1

for first, second, third in grouper([1, 7, 3, 5, 6, 8], 3):
print first, second, third

输出

1 7 3
7 3 5
3 5 6
5 6 8

如果你想要一些内联的东西,但不是特别可读,这里有另一个解决方案,使用生成器。我认为它的性能也不是最好的:-/

将 list 转换为具有在最后一项之前结束的调整的生成器:

gen = (x for x in l[:-1])

把它们转换成对子:

[(gen.next(), x) for x in l[1:]]

这就够了。

Generalizing sberry's approach to nwise with comprehension:

def nwise(lst, k=2):
return list(zip(*[lst[i:] for i in range(k)]))

例如

nwise(list(range(10)),3)

[(0,1,2) ,(1,2,3) ,(2,3,4,5) ,(4,5,6) ,(5,6, 7) ,(6,7,8) ,(7,8,9)]

一种不需要进行不必要的复制的简单方法是使用一个生成器来存储前面的元素。

def pairs(iterable):
"""Yield elements pairwise from iterable as (i0, i1), (i1, i2), ..."""
it = iter(iterable)
try:
prev = next(it)
except StopIteration:
return
for item in it:
yield prev, item
prev = item

与基于索引的解决方案不同,这种解决方案适用于任何迭代,包括那些不支持索引的解决方案(例如生成器)或缓慢的解决方案(例如 collections.deque)。