2017-09-07 161 views
4

最近我学习了关于列表和循环的知识,以及指示并删除列表中最后一项的命令.pop()Python“for in”循环打印列表中的最后一项

因此,我试图编写一个代码,逐个删除列表中的最后一个项目,直到只剩下一个项目。

的代码是:

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.") 

蟒蛇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 

我的意思是,我会,如果返回某些错误更舒适,这意味着该代码是不正确的。但为什么它能够工作,但不是一个完整的方式?

+0

你没有得到你的预期输出的原因是因为你在迭代它的同时修改迭代器。 –

+0

不要'list_A.pop()'。 – DyZ

+0

伙计们,非常感谢!我的确在玩耍,看看这些事情是如何一起工作的。显然,我不熟悉“迭代”,我明白一个while循环现在是更好的选择。 –

回答

5

您在迭代列表时突变列表。

可以使用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 
i 
h 
g 
f 
e 
d 
c 
job done 

一个更有效的方法是确定标记字符的第一个实例的索引,删除它和列表的其余部分(虽然字符不会被打印,因为它们被删除):

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 
+0

当然,您可以随时在零件被移除之前将零件切片并打印出来。 'remove = list_A [pos:]','del list_A [pos:]'(使用'del'避免使临时参与的'list_A [:] = list_A [:pos]'),' ):print(x)' – ShadowRanger

+0

这会检查每个迭代中的'c'是否在列表中,为什么不能循环最大'n'次而不是'n²*(n + 1)/ 2'。 –

+0

@ShadowRanger:是的,'del'更好。 – mhawke

1
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.") 

我们能走得更快,但我不知道无论您学到列表切片和comprehesion然而,这里有一个更好更快的解决方案:

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.') 
+0

@HubertGrzeskowiak当'c''不存在时,我不会出现异常,因为那么数组将被打印并清空,因此'while list_A:'将计算为'False',因此循环终止。 –

+0

你说得对。我的错。我想我把它与其他答案混合起来。我删除了不必要的评论。 –

+3

这个答案依赖于它应该停在第一个弹出的'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了。

+0

非常感谢您的快速回答。 我明白你所说的一切,除了'迭代'这个词。我会尝试谷歌了解这一点。 我不得不说,我确实有点混淆for循环和while循环之间。正如你所提到的for循环不应该修改列表。那么这两个循环命令之间有什么其他建议?我如何快速确定在任何场合使用哪一个? –

+0

这会检查每个迭代中的“c”是否在列表中,为什么不能循环最大n次而不是'n2 *(n + 1)/ 2'。 –

+0

@MrGeek对于这不是最高性能的解决方案,你绝对正确。但是,在这种情况下,我想尽可能保持简单,因为OP只是学习Python。 –

2

我最近回答了一个类似的问题,它归结为:不要修改你正在迭代的序列。

使用自定义的迭代器(从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

啊,自定义迭代器的好主意。 +1真的有助于展示_why_修改迭代器,同时迭代它是一个坏主意。 –