我有时需要在Python中迭代一个列表,查看“current”元素和“next”元素。到目前为止,我已经使用以下代码完成了这项工作:
for current, next in zip(the_list, the_list[1:]):
# Do something
这有效并且符合我的预期,但是有更多惯用或有效的方法来做同样的事情吗?
答案 0 :(得分:111)
以下是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
:
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
向前移动一步(next(b, None)
))。此时a
指向s0,b
指向s1。 a
和b
都可以独立遍历原始迭代器--izip函数接受两个迭代器并生成返回元素对,以相同的速度推进两个迭代器。
一个警告:tee()
函数生成两个迭代器,它们可以相互独立地前进,但它需要付出代价。如果其中一个迭代器比另一个迭代器进一步前进,那么tee()
需要将消耗的元素保留在内存中,直到第二个迭代器也将它们包含在内(它不能“回放”原始迭代器)。这里没关系,因为一个迭代器只比另一个迭代器领先一步,但一般情况下这样很容易使用大量内存。
由于tee()
可以使用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)
答案 1 :(得分:22)
滚动你自己!
def pairwise(iterable):
it = iter(iterable)
a = next(it, None)
for b in it:
yield (a, b)
a = b
答案 2 :(得分:18)
由于the_list[1:]
实际上创建了整个列表的副本(不包括其第一个元素),并且zip()
在调用时立即创建元组列表,因此总共创建了三个列表副本。如果您的列表非常大,您可能更喜欢
from itertools import izip, islice
for current_item, next_item in izip(the_list, islice(the_list, 1, None)):
print(current_item, next_item)
根本不会复制列表。
答案 3 :(得分:13)
按索引迭代可以做同样的事情:
#!/usr/bin/python
the_list = [1, 2, 3, 4]
for i in xrange(len(the_list) - 1):
current_item, next_item = the_list[i], the_list[i + 1]
print(current_item, next_item)
输出:
(1, 2)
(2, 3)
(3, 4)
答案 4 :(得分:12)
我只是把它拿出来,我很惊讶没有人想到枚举()。
for (index, thing) in enumerate(the_list):
if index < len(the_list):
current, next_ = thing, the_list[index + 1]
#do something
答案 5 :(得分:2)
这是从2020年5月16日开始的简单导入
from more_itertools import pairwise
for current, next in pairwise(your_iterable):
print(f'Current = {current}, next = {nxt}')
Docs for more-itertools 在后台,此代码与其他答案中的代码相同,但是我更喜欢在可用时导入。
如果尚未安装,则:
pip install more-itertools
示例
例如,如果您有fibbonnacci序列,则可以将后续对的比率计算为:
from more_itertools import pairwise
fib= [1,1,2,3,5,8,13]
for current, nxt in pairwise(fib):
ratio=current/nxt
print(f'Curent = {current}, next = {nxt}, ratio = {ratio} ')
答案 6 :(得分:1)
使用列表推导从列表中成对
the_list = [1, 2, 3, 4]
pairs = [[the_list[i], the_list[i + 1]] for i in range(len(the_list) - 1)]
for [current_item, next_item] in pairs:
print(current_item, next_item)
输出:
(1, 2)
(2, 3)
(3, 4)
答案 7 :(得分:0)
基本解决方案:
def neighbors( list ):
i = 0
while i + 1 < len( list ):
yield ( list[ i ], list[ i + 1 ] )
i += 1
for ( x, y ) in neighbors( list ):
print( x, y )
答案 8 :(得分:0)
code = '0016364ee0942aa7cc04a8189ef3'
# Getting the current and next item
print [code[idx]+code[idx+1] for idx in range(len(code)-1)]
# Getting the pair
print [code[idx*2]+code[idx*2+1] for idx in range(len(code)/2)]
答案 9 :(得分:0)
我真的很惊讶,没有人提到更短,更简单,最重要的通用解决方案:
Python 3:
def n_wise(iterable, n):
return zip(*(itertools.islice(iterable, i, None) for i in range(n)))
Python 2:
def n_wise(iterable, n):
return itertoolt.izip(*(itertools.islice(iterable, i, None) for i in xrange(n)))
它可以通过传递n=2
来进行成对迭代,但是可以处理更大的数字:
>>> for a, b in n_wise('Hello!', 2):
>>> print(a, b)
H e
e l
l l
l o
o !
>>> for a, b, c, d in n_wise('Hello World!', 4):
>>> print(a, b, c, d)
H e l l
e l l o
l l o
l o W
o W o
W o r
W o r l
o r l d
r l d !
答案 10 :(得分:0)
在即将到来的Python 3.10
release schedule
中,这是pairwise
函数的确切角色:
from itertools import pairwise
list(pairwise([1, 2, 3, 4, 5]))
# [(1, 2), (2, 3), (3, 4), (4, 5)]
,或者如果您不需要将结果作为pairwise([1, 2, 3, 4, 5])
,则只需list
。