21

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

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)。澄清一下aliens, 和bolts都是字典列表。

我究竟做错了什么?

4

5 回答 5

41

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

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
于 2013-01-02T17:54:57.217 回答
2

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

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

这导致您aliensb. 如果 b 在第一次循环中被删除,aliens那么当它第二次循环时,你会得到错误。

有几件事要解决。首先,改变内部循环aliens以使用 以外的东西a,所以:

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

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

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 的帖子也可能有所帮助。

于 2013-01-02T17:57:42.320 回答
1

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

因为使用remove的时候必须按name而不是index来命名被删除的item,所以在代码操作的时候会出现这个错误(value error: x is not in list)但是我们用del的时候就ok了,因为我们delete item by它的索引。无论项目的名称是什么,使用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
于 2020-04-20T23:56:16.877 回答
0

给螺栓一个“健康”,初始化为 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))
于 2013-01-03T00:51:37.167 回答
0

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

像这样

lis = [1,2,3,4,5,6]
i=0
while i in range(len(lis)) :
    lis. remove(lis[i])
于 2020-04-20T04:05:34.430 回答