如何迭代列表中重叠的(当前、下一个)值对?
- 2024-11-22 08:47:00
- admin 原创
- 181
问题描述:
我有时需要在 Python 中迭代一个列表,查看“当前”元素和“下一个”元素。到目前为止,我已经使用以下代码完成了此操作:
for current, next in zip(the_list, the_list[1:]):
# Do something
这可以达到我的预期,但是有没有更惯用或更有效的方法来做同样的事情?
这个问题的一些答案可以通过解决一次只取两个元素的具体情况来简化。对于一次取 N 个元素的一般情况,请参阅滚动或滑动窗口迭代器?。
解决方案 1:
3.8 的文档提供了这个配方:
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
来获取相同类型的惰性迭代器(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
和(调用),它们都指向原始可迭代对象的第一个元素。第二个迭代器向前移动 1 步(调用)。此时,它们指向 s0 和s1。和都可以独立遍历原始迭代器 - izip 函数采用这两个迭代器并对返回的元素进行配对,以相同的速度推进这两个迭代器。b
`tee()b
next(b, None)a
ba
b`
由于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)
警告:如果生成的迭代器之一tee
比其他迭代器前进得更快,则实现需要将消耗的元素保留在内存中,直到每个迭代器都消耗了它们(它不能“倒回”原始迭代器)。这里这并不重要,因为一个迭代器仅比另一个迭代器领先一步,但通常这种方式很容易使用大量内存。
解决方案 2:
自己动手吧!
def pairwise(iterable):
it = iter(iterable)
a = next(it, None)
for b in it:
yield (a, b)
a = b
解决方案 3:
从 Python 3.10 开始,该函数的确切作用如下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
。
解决方案 4:
我只是把这个说出来,我很惊讶没有人想到过 enumerate()。
for (index, thing) in enumerate(the_list):
if index < len(the_list):
current, next_ = thing, the_list[index + 1]
#do something
解决方案 5:
由于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)
它根本不复制列表。
解决方案 6:
通过索引迭代可以做同样的事情:
#!/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)
解决方案 7:
我真的很惊讶没有人提到更短、更简单、最重要的是通用的解决方案:
Python 3:
from itertools import islice
def n_wise(iterable, n):
return zip(*(islice(iterable, i, None) for i in range(n)))
Python 2:
from itertools import izip, islice
def n_wise(iterable, n):
return izip(*(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 !
解决方案 8:
截至 2020 年 5 月 16 日,这是一个简单的导入
from more_itertools import pairwise
for current, next in pairwise(your_iterable):
print(f'Current = {current}, next = {nxt}')
more-itertools 的文档
从本质上讲,此代码与其他答案中的代码相同,但我更喜欢在可用时导入。
如果你尚未安装,那么:pip install more-itertools
例子
例如如果你有斐波那契数列,你可以计算后续对的比率:
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} ')
解决方案 9:
正如其他人指出的那样,itertools.pairwise()
这是 Python 最新版本的必经之路。但是,对于 3.8+ 版本,一个有趣且更简洁(与已发布的其他解决方案相比)的选项不需要额外的导入,它通过海象运算符实现:
def pairwise(iterable):
a = next(iterable)
yield from ((a, a := b) for b in iterable)
解决方案 10:
一个基本的解决方案:
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 )
解决方案 11:
使用列表推导式从列表中配对
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)
解决方案 12:
temp=[-39.5, -27.5, -15.5, -3.5, 8.5, 20.5, 32.5, 44.5, 56.5, 68.5, 80.5, 92.5,104.5]
li_tup = []
count=0
i=0
new_tup=()
while i<len(temp):
if count<1:
new_tup = new_tup + (temp[i],)
count=count+1
i=i+1
else:
new_tup = new_tup + (temp[i],)
count=0
li_tup.append(new_tup)
new_tup=()
print(li_tup)
其中一种方法就是像上面那样
解决方案 13:
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)]