Python“for in”循环打印列表中的最后一项
Posted
技术标签:
【中文标题】Python“for in”循环打印列表中的最后一项【英文标题】:Python "for in" loop to print the last item in the list 【发布时间】:2018-02-15 14:34:17 【问题描述】:最近我学习了列表和 for 循环,以及指示和删除列表中最后一项的命令 .pop()
。
所以我尝试编写代码来逐个删除列表中的最后一项,直到它只剩下一项。
代码是:
list_A = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
for i in list_A:
print(list_A.pop())
if 'c' not in list_A:
break
print("job done.")
python 3.6 的输出给了我这个:
/Library/Frameworks/Python.framework/Versions/3.6/bin/python3.6
j
i
h
g
f
job done.
如您所见,它确实有效,但只成功了一半?
我期待:
j
i
h
g
f
e
d
c
job done
我的意思是,如果它返回一些错误,我会更舒服,这意味着代码不正确。但是为什么它起作用了,但没有完全通过?
【问题讨论】:
没有得到预期输出的原因是您在迭代时修改了可迭代对象。 不要list_A.pop()
。
各位,非常感谢!!!我确实在玩,看看这些东西是如何协同工作的。显然,我对“迭代”并不熟悉,我知道现在使用 while 循环是一个更好的选择。
【参考方案1】:
您在迭代列表时正在改变它。
您可以使用while
循环来执行此操作:
list_A = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
while 'c' in list_A:
print(list_A.pop())
print('job done')
输出:
j 一世 H G F e d C 任务完成
一种更有效的方法是确定标记字符的第一个实例的索引,然后删除它和列表的其余部分(尽管这些字符在被删除时不会被打印出来):
try:
pos = list_A.index('c')
list_A[:] = list_A[:pos]
# del list_A[pos:] # more efficient alternative suggested by @ShadowRanger
except ValueError as e:
pass
【讨论】:
当然,您总是可以在拆下零件之前将其切出,然后再打印出来。removed = list_A[pos:]
,del list_A[pos:]
(使用del
避免使临时参与list_A[:] = list_A[:pos]
),for x in reversed(removed): print(x)
这会检查 c
是否在每次迭代的列表中,为什么你不能循环 n
次 max 而不是 n²*(n+1)/2
。
@ShadowRanger:是的,del
更好。
@MrGeek:你可以。它只是演示代码 - 我不建议在实践中这样做。无论如何,我已经提供了一个更高效的版本。
@mhawke 太好了。更好。【参考方案2】:
list_A = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
while list_A: # while list_A has elements, in case 'c' wasn't present
el = list_A.pop() # save the last element
print(el)
if 'c'==el: # if 'c' was popped (reached)
break
print("job done.")
这样,即使'c'
不存在,它也会打印所有内容然后退出。这也避免了在每次迭代中检查'c'
是否存在,这需要时间。
根据@MSeifert 的评论,如果循环不应该在第一个弹出的c
处停止,而是在列表没有c
时停止,对上面的代码稍作修改会导致:
list_A = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'c', 'h', 'i', 'j']
while list_A:
print(list_A.pop())
if 'c' not in list_A:
break
print("job done.")
我们可以走得更快,但我不知道你是否学习了列表切片和理解,所以这里有一个更好更快的解决方案:
list_A = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
try:
p=list_A.index('c')
r='\n'.join(list_A[list_A.index('c'):][::-1])
except ValueError:
r='\n'.join(list_A[::-1])
print(r)
print('job done.')
【讨论】:
@HubertGrzeskowiak 当'c'
不存在时我不会得到异常,因为随后数组将被打印并清空,因此while list_A:
将评估为False
,因此循环终止。
你是对的。我的错。我想我把它和另一个答案混在一起了。我删除了不必要的评论。
这个答案依赖于它应该在第一个弹出的'c'
处停止的假设,而问题包含表明它应该在列表中没有'c'
时立即停止的代码。对于一个'c'
,这是等效的,但如果它包含多个(或没有),结果会有所不同。
@MSeifert 我没注意,谢谢。无论如何,我更新了我的答案。
感谢您的更新。我再次删除了反对票:)【参考方案3】:
在 Python 中使用 for..in
循环时,您不应该修改列表。
这里发生的事情如下:
循环从第一项到最后一项,所以它从a
开始
pop()
删除最后一个列表条目,因此在第一次循环迭代中,您摆脱了最后一个字母 j
并打印它
接下来的 5 个字母继续进行。您从左侧迭代它们,但同时删除右侧的最后一个
遇到e
时,您从列表中删除并打印f
之后列表包含字母 a
到 e
并且由于您刚刚迭代了 e
,因此循环的工作已完成
真的很难说出你想在这里做什么,因为它更多的是玩弄而不是完成某事。我建议使用while
循环,只要您打算从循环内编辑列表。您具有适当语义的示例可能如下所示:
while list_A:
print(list_A.pop())
if "c" not in list_A:
break
只要列表中有项目,此循环就会继续,并且只有在列表中不再有 c
时才会停止。
【讨论】:
非常感谢您的快速回答。我理解你所说的一切,除了“迭代”这个词。我会尝试用谷歌搜索来理解。而且我不得不说我确实对for循环和while循环有点困惑。正如您提到的那样,for 循环不应该修改列表。那么这两个循环命令之间还有其他建议吗?如何快速判断在任何场合使用哪一个? 这会在每次迭代时检查c
是否在列表中,为什么你不能循环n
次max 而不是n²*(n+1)/2
。
@MrGeek 你说得对,这不是最高效的解决方案。不过,在这种情况下,我想让它尽可能简单,因为 OP 只是在学习 Python。
@HubertGrzeskowiak 我知道,我的解决方案也不是最好的,我只是认为会有更好的方法。
@MrGeek 如果没有问题定义,就不可能说出最佳解决方案,OP 想了解他的代码,我想我们都帮助解释了它。【参考方案4】:
我最近回答了一个类似的问题,它归结为:不要修改您正在迭代的序列。
使用自定义迭代器(来自another answer of mine)显示发生了什么:
class CustomIterator(object):
def __init__(self, seq):
self.seq = seq
self.idx = 0
def __iter__(self):
return self
def __next__(self):
print('give next element:', self.idx)
for idx, item in enumerate(self.seq):
if idx == self.idx:
print(idx, '--->', item)
else:
print(idx, ' ', item)
try:
nxtitem = self.seq[self.idx]
except IndexError:
raise StopIteration
self.idx += 1
return nxtitem
next = __next__ # py2 compat
list_A = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
for i in CustomIterator(list_A):
print(list_A.pop())
if 'c' not in list_A:
break
哪些打印:
give next element: 0
0 ---> a
1 b
2 c
3 d
4 e
5 f
6 g
7 h
8 i
9 j
j
give next element: 1
0 a
1 ---> b
2 c
3 d
4 e
5 f
6 g
7 h
8 i
i
give next element: 2
0 a
1 b
2 ---> c
3 d
4 e
5 f
6 g
7 h
h
give next element: 3
0 a
1 b
2 c
3 ---> d
4 e
5 f
6 g
g
give next element: 4
0 a
1 b
2 c
3 d
4 ---> e
5 f
f
give next element: 5
0 a
1 b
2 c
3 d
4 e
所以它并没有因为break
而结束,而是因为它遍历了整个列表(或者更好:直到没有更多的项目!)。
另外'c' not in listA
是O(n)
操作,所以你的循环实际上是O(n**2)
。为什么不直接找到'c'
的第一个索引,然后简单地迭代直到出现:
list_A = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
try:
c_index = list_A.index('c')
except ValueError:
# no 'c' in the list, probably should do something more useful here ...
pass
else:
for item in reversed(list_A[c_index:]): # print the items
print(item)
del list_A[c_index:] # remove the items from the list
打印(如预期):
j
i
h
g
f
e
d
c
【讨论】:
啊,自定义迭代器的好主意。 +1 确实有助于演示为什么在迭代迭代时修改可迭代对象是一个坏主意。以上是关于Python“for in”循环打印列表中的最后一项的主要内容,如果未能解决你的问题,请参考以下文章