从列表中删除类

时间:2016-02-29 22:27:52

标签: python list class python-3.x

我正在尝试根据他们的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

我不确定如何从战场上移除死者。任何提示都表示赞赏。如果我以一种根本错误的方式解决这个问题,请告诉我。

6 个答案:

答案 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)

但这不会像第一种选择那样有效。