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 之后列表包含字母 ae 并且由于您刚刚迭代了 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 listAO(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”循环打印列表中的最后一项的主要内容,如果未能解决你的问题,请参考以下文章

Python中的迭代遍历 for in

JS中的forEach,for in,for of和for的遍历优缺点及区别

Python for-in Loop常见遍历方法

python中for in的用法

从 for 循环打印时出现问题

Python(36)_循环打印列表中的列表