【问题标题】:Python throws ValueError: list.remove(x): x not in listPython 抛出 ValueError: list.remove(x): x not in list
【发布时间】:2020-05-14 15:15:44
【问题描述】:

每次我运行这个程序,我都会得到这个错误:

ValueError: list.remove(x): x not in list

我试图在单个外星人被螺栓击中时降低其生命值。如果它的健康状况为<= 0,则该外星人也应该被摧毁。同样,螺栓也会被破坏。这是我的代码:

def manage_collide(bolts, aliens):
    # Check if a bolt collides with any alien(s)
    for b in bolts:
        for a in aliens:
            if b['rect'].colliderect(a['rect']):
                for a in aliens:
                    a['health'] -= 1
                    bolts.remove(b)
                    if a['health'] == 0:
                        aliens.remove(a)
    # Return bolts, aliens dictionaries
    return bolts, aliens

ValueError 发生在aliens.remove(a) 行上。澄清一下,aliensbolts 都是字典列表。

我做错了什么?

【问题讨论】:

  • ValueError 在哪一行?
  • 为了将来参考,这段代码的问题是我在外星人列表上循环了两次,这在尝试从列表中删除时会导致一些问题。删除第二个“for a in aliens”可以防止这个问题。

标签: python


【解决方案1】:

您不应从正在循环的列表中删除项目。改为创建副本:

for a in aliens[:]:

for b in bolts[:]:

在循环时修改列表会影响循环:

>>> lst = [1, 2, 3]
>>> for i in lst:
...     print i
...     lst.remove(i)
... 
1
3
>>> lst
[2]

从您循环两次的列表中删除项目会使事情变得更加复杂,从而导致 ValueError:

>>> lst = [1, 2, 3]
>>> for i in lst:
...     for a in lst:
...         print i, a, lst
...         lst.remove(i)
... 
1 1 [1, 2, 3]
1 3 [2, 3]
Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
ValueError: list.remove(x): x not in list

当您在循环的每个 级别创建要修改的列表的副本时,您可以避免该问题:

>>> lst = [1, 2, 3]
>>> for i in lst[:]:
...     for i in lst[:]:
...         print i, lst
...         lst.remove(i)
... 
1 [1, 2, 3]
2 [2, 3]
3 [3]

当你发生碰撞时,你只需要移除b螺栓一次,而不是在你伤害外星人的循环中。稍后单独清理外星人:

def manage_collide(bolts, aliens):
    for b in bolts[:]:
        for a in aliens:
            if b['rect'].colliderect(a['rect']) and a['health'] > 0:
                bolts.remove(b)
                for a in aliens:
                    a['health'] -= 1
    for a in aliens[:]:
        if a['health'] <= 0:
            aliens.remove(a)
    return bolts, aliens

【讨论】:

  • 这实际上并没有回答 OP 的问题。在迭代列表时从列表中删除项目实际上不是问题。只是如果你不知道它是如何工作的,它可能会产生意想不到的结果。
  • 当仅将该行更改为副本列表时,它仍然会在同一行 Aliens.remove(a) 上放置一个 ValueError。
  • @kindall:是双循环让它变得更有趣,并且可能导致值错误。
  • 这对我仍然不起作用。或许你可以直接修改我的代码?
【解决方案2】:

您的代码中存在导致此问题的错误。简化后的代码如下所示:

for b in bolts:
  for a in aliens:
    for a in aliens:
      bolts.remove(b)

这导致您为b 中的每个条目循环多次aliens。如果 b 在 aliens 的第一次循环中被删除,那么当它第二次循环时,您将得到错误。

需要解决的一些问题。首先,在aliens 上的内部循环中更改为使用a 以外的其他内容,因此:

for b in bolts:
  for a in aliens:
    for c in aliens:
      if hit:
        bolts.remove(b)

其次,只从bolts 中删除b 一次。所以:

for b in bolts:
  for a in aliens:
    should_remove = False
    for c in aliens:
      if hit:
        should_remove = True
    if should_remove:
      bolts.remove(b)

我认为此代码还有其他问题,但这是您的主要问题的原因。 Martijn 的帖子也可能有所帮助。

【讨论】:

    【解决方案3】:

    你不能使用 list.remove 你应该使用 del list[x]

    因为在使用remove的时候必须按name而不是index来命名被删除的item,所以在代码操作的时候会出现这个错误(value error: x is not in list) 但是当我们使用 del 时它是可以的,因为我们通过它的索引删除项目。 无论项目的名称是什么,使用del,代码都会正确运行 我希望我清除了问题并解决了它

    要知道我的确切意思 请尝试此代码 然后通过用 remove 替换 del 来尝试它,你就会明白我的意思。 代码如下:

    aliens = [[4,3,2,1],[4,3,2,1],[4,3,2,1]]
    print(aliens)
    bolts = [b for b in range(1,30)]
    for b in bolts:
        del aliens[0][0]
        print(aliens) 
            if len(aliens[0]) == 0:
                del aliens[0]
        if len(aliens) == 0
                    print("you win")
            break
    

    【讨论】:

    • 虽然此代码可以解决问题,including an explanation 说明如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提出问题的人。请edit您的回答添加解释并说明适用的限制和假设。
    【解决方案4】:

    也给螺栓一个“健康”,初始化为 1。然后您可以执行一个嵌套循环来计算所有伤害,并执行两个单独的未嵌套“循环”来移除所有“死亡”。除了,不要那样做,因为你仍然不想修改你正在循环的列表。制作副本仍然太复杂。您真正想要做的是直接构建一个仅包含仍然“活着”的事物的新列表,您可以使用列表推导式(或如此处所示,使用filter)进行描述性地做到这一点。

    # for example
    class Alien:
        # ... other stuff
        def damage(self): self.hp -= 1
        def alive(self): return self.hp > 0
    
    # similarly for Bolt
    
    def collide(an_alien, a_bolt):
        # etc.
    
    def handle_collisions(aliens, bolts):
        for a in aliens:
            for b in bolts:
                if collide(a, b):
                    a.damage()
                    b.damage()
    
        return list(filter(Alien.alive, aliens)), list(filter(Bolt.alive, bolts))
    

    【讨论】:

      【解决方案5】:

      我认为如果你用 while 循环替换 for 循环 - 只有在你从列表中删除的循环中 - 会解决它

      这样

      lis = [1,2,3,4,5,6]
      i=0
      while i in range(len(lis)) :
          lis. remove(lis[i])
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-02-23
        • 2021-11-03
        • 2022-06-28
        • 2022-06-11
        • 2020-07-11
        • 2022-12-17
        • 1970-01-01
        相关资源
        最近更新 更多