我正在尝试根据他们的hp从列表中删除类。我正在为D& D活动制作一个大型战斗模拟器。它是一个简单的程序,可以生成两个类列表,并将它们相互对立。
在解除死亡战士方面,我遇到了一个问题。如果一个战斗机在一个圆形中死亡,它可以正常工作,但是当多个死亡时,它会变得不稳定。
def check_human_deaths():
for i in range(len(goodguys)):
if goodguys[i].hp <= 0:
print('{} has died...'.format(goodguys[i].name))
goodguys.remove(goodguys[i])
删除死战士会改变列表的长度,引发索引错误:
IndexError: list index out of range
我不确定如何从战场上移除死者。任何提示都表示赞赏。如果我以一种根本错误的方式解决这个问题,请告诉我。
答案 0 :(得分:3)
两种选择:
修改列表的副本并将其结果用作新列表:
>>> lst = [1,2,3,4,5]
>>> for i in lst[:]:
... if i % 2:
... result.append(i)
...
>>> lst = result
>>> lst
[1, 3, 5]
修改列表,但反向修改列表以避免弄乱索引:
>>> lst = [1,2,3,4,5]
>>> for i in lst[::-1]:
... if not i % 2:
... lst.remove(i)
...
>>> lst
[1, 3, 5]
答案 1 :(得分:1)
问题是当你从goodguys中删除时,索引减少了一个。例如:
1,2,3,4
删除2
1,3,4
三个索引减1,大小减1。
答案 2 :(得分:1)
goodguys = [ guy for guy in goodguys if guy.hp > 0 ]
这将过滤掉你阵列中任何死的goodguys。
你可以在你的函数中使用它:
def check_human_deaths():
global goodguys
dedguys = [ guy for guy in goodguys if guy.hp <= 0 ]
for guy in dedguys:
print('{} has died...'.format(guy.name))
goodguys = [ guy for guy in goodguys if guy.hp > 0 ]
答案 3 :(得分:0)
您收到此错误是因为您正在迭代列表的长度,请说l
。每次调用list.remove()
时,列表的长度都会减少1
,并且您的程序会因为list[l]
不存在而导致索引错误。相反,您可以使用:
def check_human_deaths():
for goodguy in list(goodguys):
if goodguy.hp <= 0:
print('{} has died...'.format(goodguy.name))
goodguys.remove(goodguy)
注意:list(goodguys)
将创建goodguys
列表的副本,防止在从列表中删除对象时出现for
循环的奇怪行为:
>>> t= [1,2,3]
>>> x= list(t)
>>> x.remove(1)
>>> x
[2, 3]
>>> t
[1, 2, 3]
即使从x中删除了该值,该值仍然会出现在t中,并且您的for
循环不会表现得很奇怪
答案 4 :(得分:0)
正如其他人所说,你不能在迭代时更改列表,因为会发生奇怪的事情。相反,您可以保存要删除的元素,并在循环后删除它们:
def check_human_deaths():
things_to_delete = []
for i in range(len(goodguys)):
if goodguys[i].hp <= 0:
print('{} has died...'.format(goodguys[i].name))
things_to_delete.append(goodguys[i])
goodguys = [x for x in goodguys if x not in things_to_delete]
答案 5 :(得分:0)
您可以使用生成器功能来执行此操作,以便以更有效和正确的方式打印和更新列表,对列表进行一次传递:
class Foo():
def __init__(self, hp, name):
self.hp = hp
self.name = name
def check_human_deaths(goodguys):
for guy in goodguys:
if guy.hp < 1:
print('{} has died...'.format(guy.name))
else:
yield guy
演示:
In [29]: goodguys = [Foo(0,"foo"), Foo(1,"bar"), Foo(2,"foobar"), Foo(-1,"barf")]
In [30]: goodguys[:] = check_human_deaths(goodguys)
foo has died...
barf has died...
In [31]:
In [31]: print(goodguys)
[<__main__.Foo instance at 0x7fdab2c74dd0>, <__main__.Foo instance at 0x7fdab2c6e908>]
这个answer有一个很好的解释,为什么你永远不应该改变你正在迭代的列表。
此外,如果您要从列表末尾开始并使用删除,则可以使用颠倒而不是创建列表的另一个副本:
for guy in reversed(goodguys):
if guy.hp <= 0:
print('{} has died...'.format(guy.name))
goodguys.remove(guy)
但这不会像第一种选择那样有效。