【问题标题】:Modifying list while iterating [duplicate]迭代时修改列表[重复]
【发布时间】:2019-04-04 06:34:54
【问题描述】:
l  = range(100)                         
for i in l:                         
    print i,                         
    print l.pop(0),                  
    print l.pop(0)

上面的 python 代码给出的输出与预期的完全不同。我想循环遍历项目,以便在循环时跳过一个项目。

请解释一下。

【问题讨论】:

  • 无法通过查看代码来判断您希望实现的目标。
  • “与预期不同”。真的吗?你期待什么?

标签: python list iterator loops


【解决方案1】:

一般的经验法则是在迭代集合/数组/列表时不要修改它。

使用辅助列表来存储您想要操作的项目,并在初始循环之后在循环中执行该逻辑。

【讨论】:

    【解决方案2】:

    试试这个。它可以避免改变你正在迭代的东西,这通常是一种代码味道。

    for i in xrange(0, 100, 3):
        print i
    

    xrange

    【讨论】:

    • Python 3.0 range() 现在的行为类似于 xrange() 过去的行为,除了它适用于任意大小的值。后者不再存在。
    【解决方案3】:

    我之前被(其他人的)“聪明”代码所困扰,该代码在迭代列表时尝试修改列表。我决定在任何情况下都不会这样做。

    您可以使用切片运算符mylist[::3] 跳至列表中的每第三项。

    mylist = [i for i in range(100)]
    for i in mylist[::3]:
        print(i)
    

    关于我的示例的其他要点与 python 3.0 中的新语法有关。

    • 我使用列表推导来定义 mylist,因为它适用于 Python 3.0(见下文)
    • print 是 python 3.0 中的一个函数

    Python 3.0 range() 现在的行为类似于 xrange() 过去的行为,除了它适用于任意大小的值。后者不再存在。

    【讨论】:

    • 如果需要一个列表对象,list(range(100)) 比这种徒劳的列表理解更快更直接。此外,for i in range(100)[::3]: 有效。
    • 另外,如果你只是想迭代整数,最好还是使用range(0, 100, 3) 甚至xrange(0, 100, 3)(后者不会在 ram 中列出完整的列表)。
    • @Lenna,[range(100)] 怎么样?
    • @wsysuper 尝试打印你的建议,你会明白为什么它不好:)
    • 试试 [*range(100)]。
    【解决方案4】:

    永远不要更改您正在循环的容器,因为该容器上的迭代器不会被告知您的更改,而且正如您所注意到的,这很可能会产生非常不同的循环和/或不正确的循环.在正常情况下,在容器的副本上循环会有所帮助,但在您的情况下,很明显您想要这样,因为在循环 50 条腿后容器将是空的,如果你那时再次尝试弹出你会得到一个异常。

    有什么但不清楚的是,你想要实现什么行为,如果有的话?!也许你可以用while...表达你的愿望?

    i = 0
    while i < len(some_list):
        print i,                         
        print some_list.pop(0),                  
        print some_list.pop(0)
    

    【讨论】:

    • 等待你在循环中增加 i 吗?
    • @maq 没必要。 pop 实际上删除了该元素。所以你继续查看元素0 并弹出它。按预期工作。
    • 亚历克斯,我发现这适用于琐碎的例子,我们还应该避免这种情况吗?例如>>> l = list('abcdefab') >>> for i in l: if l.count(i) > 1: l.remove(i)
    • @hacks,因为容器甚至不跟踪它上面的迭代器,更不用说钩子甚至改变方法来循环遍历每个这样的迭代器,并以某种方式神奇地让每个迭代器知道改动。这将是很多微妙、复杂的代码,并且检查会减慢非常频繁的操作。尝试编写一个类似列表的容器,例如,for i, x in enumerate(container): 可以完美地工作,因为循环的主体选择性地删除了一些容器的项目,您将更好地掌握这些问题 -- 嵌套循环下一个,然后再下一个,...:-)
    • 迭代器不拥有也不持有任何项目——它进入列表(在迭代器的当前索引处——那个索引是迭代器拥有的唯一东西,并且保持)每次它需要为next 提供一个值(并且在那之后还增加它的内部迭代器)。
    【解决方案5】:

    此切片语法会复制列表并执行您想要的操作:

    l  = range(100)  
    for i in l[:]:  
        print i,  
        print l.pop(0),  
        print l.pop(0)
    

    【讨论】:

    • 我看到这个很晚,但这个答案是错误的。提供的代码在迭代超过 50 个项目后会崩溃,因为它每次通过循环都会从原始列表中删除两个项目,但不会跳过切片中的任何项目。
    【解决方案6】:

    我想这就是你想要的:

    l  = range(100)  
    index = 0                       
    for i in l:                         
        print i,              
        try:
            print l.pop(index+1),                  
            print l.pop(index+1)
        except IndexError:
            pass
        index += 1
    

    当要弹出的项目数量是运行时决定时,编码非常方便。 但是运行效率很差,代码也很难维护。

    【讨论】:

      【解决方案7】:

      使用 while 循环检查数组的真实性:

      while array:
          value = array.pop(0)
          # do some calculation here
      

      而且它应该没有任何错误或有趣的行为。

      【讨论】:

      • 只要确保在每个循环中至少弹出一次即可。
      猜你喜欢
      • 2017-12-05
      • 1970-01-01
      • 2014-09-17
      • 2023-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多