如何访问 for 循环中的上一个/下一个元素?
Posted
技术标签:
【中文标题】如何访问 for 循环中的上一个/下一个元素?【英文标题】:How to access the previous/next element in a for loop? 【发布时间】:2010-09-24 08:05:33 【问题描述】:有没有办法在使用for
循环遍历它时访问list
(或tuple
,或其他可迭代的)下一个或上一个元素?
l = [1, 2, 3]
for item in l:
if item == 2:
get_previous(l, item)
【问题讨论】:
【参考方案1】:迭代器只有 next() 方法,所以你不能向前或向后看,你只能得到下一项。
enumerate(iterable) 在迭代列表或元组时会很有用。
【讨论】:
【参考方案2】:最简单的方法是在列表中搜索项目:
def get_previous(l, item):
idx = l.find(item)
return None if idx == 0 else l[idx-1]
当然,这仅适用于列表仅包含唯一项目的情况。另一种解决方案是:
for idx in range(len(l)):
item = l[idx]
if item == 2:
l[idx-1]
【讨论】:
【参考方案3】:我认为没有直接的方法,尤其是因为可迭代对象可以是 generator(没有回头路)。您可以使用sequences 将元素的索引传递到循环体中:
for index, item in enumerate(l):
if index > 0:
previous_item = l[index - 1]
else:
previous_item = None
enumerate()
函数是内置函数。
【讨论】:
【参考方案4】:表示为生成器函数:
def neighborhood(iterable):
iterator = iter(iterable)
prev_item = None
current_item = next(iterator) # throws StopIteration if empty.
for next_item in iterator:
yield (prev_item, current_item, next_item)
prev_item = current_item
current_item = next_item
yield (prev_item, current_item, None)
用法:
for prev,item,next in neighborhood(l):
print prev, item, next
【讨论】:
在这种情况下,我可能会执行“prev, item = item, next”。 要无限循环(无 StopIteration),请执行from itertools import cycle
并将第二行更改为:iterator = cycle(iterable)
在这种情况下使用 enumerate 是不是不太像 Pythonic?
您正在寻找的答案是 Vicky Liau 的,在这个下面的那个。或者,如果您希望它适用于任何可迭代而不仅仅是列表/元组/strs 等,one using itertools
.
对于 python 3.10 - 用户可以使用 itertools.pairwise 函数,请参阅 ***.com/a/69584524/3361462【参考方案5】:
在处理需要一些上下文的生成器时,我经常使用以下实用函数在迭代器上提供滑动窗口视图:
import collections, itertools
def window(it, winsize, step=1):
"""Sliding window iterator."""
it=iter(it) # Ensure we have an iterator
l=collections.deque(itertools.islice(it, winsize))
while 1: # Continue till StopIteration gets raised.
yield tuple(l)
for i in range(step):
l.append(it.next())
l.popleft()
它会一次生成一个序列 N 项的视图,移动步骤。例如。
>>> list(window([1,2,3,4,5],3))
[(1, 2, 3), (2, 3, 4), (3, 4, 5)]
当在前瞻/后视情况下使用时,您还需要处理没有下一个或前一个值的数字,您可能需要使用适当的值(例如 None)填充序列。
l= range(10)
# Print adjacent numbers
for cur, next in window(l + [None] ,2):
if next is None: print "%d is the last number." % cur
else: print "%d is followed by %d" % (cur,next)
【讨论】:
如果您使用的是itertools
,请使用Francisco Couzo 的itertools.tee
答案:***.com/a/41047005【参考方案6】:
紧接在前?
你的意思是下面的,对吧?
previous = None
for item in someList:
if item == target: break
previous = item
# previous is the item before the target
如果你想要 n 个之前的项目,你可以用一种大小为 n 的循环队列来做到这一点。
queue = []
for item in someList:
if item == target: break
queue .append( item )
if len(queue ) > n: queue .pop(0)
if len(queue ) < n: previous = None
previous = previous[0]
# previous is *n* before the target
【讨论】:
【参考方案7】:l = [1, 2, 3]
for i, item in enumerate(l):
if item == 2:
previous = l[i - 1]
print(previous)
输出:
1
如果您要查找的项目是列表中的第一项,这将环绕并返回列表中的最后一项。换句话说,将上述代码中的第三行更改为if item == 1:
将导致它打印3
。
【讨论】:
如果你的列表只有一个元素l = [2]
,这将返回与前一个元素相同的元素。【参考方案8】:
查看Tempita project 中的looper 实用程序。它为您提供了一个围绕循环项目的包装器对象,该对象提供诸如上一个、下一个、第一个、最后一个等属性。
看一下looper类的source code,很简单。还有其他这样的循环助手,但我现在不记得其他任何人了。
例子:
> easy_install Tempita
> python
>>> from tempita import looper
>>> for loop, i in looper([1, 2, 3]):
... print loop.previous, loop.item, loop.index, loop.next, loop.first, loop.last, loop.length, loop.odd, loop.even
...
None 1 0 2 True False 3 True 0
1 2 1 3 False False 3 False 1
2 3 2 None False True 3 True 0
【讨论】:
链接都坏了。【参考方案9】:不是很pythonic,但可以完成并且很简单:
l=[1,2,3]
for index in range(len(l)):
if l[index]==2:
l[index-1]
TO DO:保护边缘
【讨论】:
这与@Rudiger Wolf 的回答***.com/a/324273 完全一样【参考方案10】:我知道这是旧的,但为什么不直接使用enumerate
?
l = ['adam', 'rick', 'morty', 'adam', 'billy', 'bob', 'wally', 'bob', 'jerry']
for i, item in enumerate(l):
if i == 0:
previous_item = None
else:
previous_item = l[i - 1]
if i == len(l) - 1:
next_item = None
else:
next_item = l[i + 1]
print('Previous Item:', previous_item)
print('Item:', item)
print('Next Item:', next_item)
print('')
pass
如果你运行它,你会看到它会抓取上一个和下一个项目,而不关心列表中的重复项目。
【讨论】:
为什么投反对票?这很好,不涉及外部库或特殊功能。 该问题还要求上一项。如果一个项目重复,这不会错误地工作吗?[1,2,1,3]
?
@Teepeemm,是的,我会更新一个符合要求的版本。【参考方案11】:
l = [1, 2, 3]
for i, j in zip(l, l[1:]):
print(i, j)
【讨论】:
我使用了这个,但为了避免删除开始/结束项而进行了扩展:for prev,cur,next in zip([None]+l[:-1], l, l[1:]+[None]):
您可以避免像这样删除开始/结束项目:l = [None, *l, None]
然后for prev, cur, nxt in zip(l, l[1:], l[2:]):
【参考方案12】:
如果您希望解决方案适用于可迭代对象,itertools
documentation 有一个配方可以使用 itertools.tee()
完全满足您的需求:
import itertools
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = itertools.tee(iterable)
next(b, None)
return zip(a, b)
【讨论】:
【参考方案13】:我知道这是一个老问题,但我发现展示一个简单的解决方案很重要,该解决方案也适用于生成器和其他类型的可迭代对象,而不像大多数仅适用于列表类对象的答案。这有点类似于布赖恩的回答和这里的解决方案:https://www.programcreek.com/python/example/1754/itertools.tee
import itertools
iter0, iter1 = itertools.tee(iterable)
for item, next_item in itertools.zip_longest(
iter0,
itertools.islice(iter1, 1, None)
):
do_something(item, next_item)
或者,在第二个可迭代对象上调用 next
(如果您确定它至少有一个元素):
import itertools
iter0, iter1 = itertools.tee(iterable)
_ = next(iter1)
for item, next_item in itertools.zip_longest(iter0, iter1):
do_something(item, next_item)
【讨论】:
【参考方案14】:对于升级到python 3.10的任何人,该功能直接添加到 itertools
import itertools
l = [1,2,3]
for x, y in itertools.pairwise(l):
print(x, y)
# 1 2
# 2 3
【讨论】:
【参考方案15】:如果您不想导入任何内容,这里是一个使用 for 循环访问生成器上一项的示例。它使用类变量在下一次调用之前存储每个下一个结果。如果您想要的不仅仅是前一个项目,这个变量可能是一个小列表。类内部是一个方法生成器,它有效地扩展了 next() 内置函数以包含上一个项目分配。
代码(Python 3.10):
def previous():
class Plusprev():
def __init__(pp, gen=None):
pp.g = gen
pp.nxt = ''
pp.prev = 'start'
def ppnext(pp):
while pp.nxt != 'done':
pp.nxt = next(pp.g,'done')
yield pp.nxt
pp.prev = pp.nxt
sqgen = (n*n for n in range(13))
ppcl = Plusprev(sqgen)
nxtg = ppcl.ppnext()
nxt = next(nxtg,'done')
while nxt != 'done':
print('\nprevious ',ppcl.prev)
print('current ',nxt)
nxt = next(nxtg,'done')
previous()
这使用了内置函数,next(),默认参数。
【讨论】:
以上是关于如何访问 for 循环中的上一个/下一个元素?的主要内容,如果未能解决你的问题,请参考以下文章
如何在已排序的 xsl:for-each 循环中访问前一个和下一个元素的值