在python中从列表中删除项目的问题

时间:2013-10-28 03:55:41

标签: python list

在下面的方法中,我已经组装了一个元组列表,同时试图确保没有任何值小于零。下面的方法首先采用一个块并使用它以1为增量计算相邻块的坐标,然后继续删除其坐标小于零的块。我的问题在于第二阶段,因为如果我输入一个坐标为(0,0)的块:(0,-1)和(-1,0),它就不会删除两个坐标。

代码如下:

def get_block_neighbors(self, block):
    neighbor_list = []
    neighbor_list.append((block.x,block.y+1))
    neighbor_list.append((block.x+1,block.y+1))
    neighbor_list.append((block.x+1,block.y))
    neighbor_list.append((block.x+1,block.y-1))
    neighbor_list.append((block.x,block.y-1))
    neighbor_list.append((block.x-1,block.y-1))
    neighbor_list.append((block.x-1,block.y))
    neighbor_list.append((block.x-1,block.y+1))

    for item in neighbor_list: #each tuple item in the list
        if item[0] < 0 or item[1] < 0:
            print item
            neighbor_list.remove(item)
    print neighbor_list

get_block_neighbors(Block(Point(0,0),"green"))

我得到以下输出:

(1, -1)
(-1, -1)
(-1, 1)
[(0, 1), (1, 1), (1, 0), (0, -1), (-1, 0)]

这里,前三行是我要删除的元组的打印输出,而最后一行是我组装的元组列表。如您所见,最后两个元组的至少一个坐标具有负值。理想情况下,我想要这个:

(1, -1)
(-1, -1)
(-1, 1)
(0, -1)
(-1, 0)
[(0, 1), (1, 1), (1, 0)] 

奇怪的是,当我删除/注释掉行neighbor_list.remove(item)时,我在某种意义上更接近我需要的位置,因为打印输出中的方法包含我想要的两个元组除去。但是,当然,执行此操作的一个缺点是我不再从此列表中删除任何目标元组。

对此的任何帮助都将非常感激,我真的希望我的疏忽不是非常明显的。在旁注中,我觉得应该有一种方法来组合这个列表,同时能够放弃一个删除阶段,这就是我在解决上面的代码之前开始编写这个方法的方法。谢谢!

6 个答案:

答案 0 :(得分:3)

问题是您在迭代该列表的同时从列表中删除项目。列表迭代是通过索引(在幕后)发生的,所以这不会像你期望的那样工作,因为当删除它们的前辈时会跳过一些值。

要避免此问题,您可以使用切片迭代列表的副本:

for item in neighbor_list[:]:

或者,更好的是,使用列表推导来构建新列表而不是修改旧列表:

new_list = [(x, y) for x, y in neighbor_list if x >= 0 and y >= 0]

答案 1 :(得分:1)

您不应该从正在迭代的列表中删除项目。首先复制列表,然后迭代它。

答案 2 :(得分:1)

问题在于你正在删除列表的元素,同时你正在迭代它。如果您只是创建一个删除了元素的新列表,那就更简单了:

[item for item in neighbor_list if item[0] >= 0 and item[1] >= 0]

答案 3 :(得分:1)

首先制作一份清单:

for item in neighbor_list[:]: #each tuple item in the list
    if item[0] < 0 or item[1] < 0:
        print item
        neighbor_list.remove(item)
print neighbor_list

答案 4 :(得分:0)

周围更容易:

def get_block_neighbors(self, block):
    neighbor_list = []
    neighbor_list.append((block.x,block.y+1))
    neighbor_list.append((block.x+1,block.y+1))
    neighbor_list.append((block.x+1,block.y))
    if block.y > 0:
        neighbor_list.append((block.x+1,block.y-1))
        neighbor_list.append((block.x,block.y-1))
        if block.x > 0:
            neighbor_list.append((block.x-1,block.y-1))
    if block.x > 0:
        neighbor_list.append((block.x-1,block.y))
        neighbor_list.append((block.x-1,block.y+1))

    return neighbor_list

答案 5 :(得分:0)

这是一个示例,显示了一些看起来像是试图从列表中过滤某些数字的代码

>>> L = range(10)
>>> for x in L:
...     print x, L
...     if x in (4,5,6,7):
...         L.remove(x)
... 
0 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
2 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
3 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
4 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
6 [0, 1, 2, 3, 5, 6, 7, 8, 9]
8 [0, 1, 2, 3, 5, 7, 8, 9]
9 [0, 1, 2, 3, 5, 7, 8, 9]

在迭代列表时删除项目通常是个坏主意。

这是获取邻居列表的更简单方法。它完全不需要.remove

def get_block_neighbors(self, block):
    x = block.x
    y = block.y
    xrange = (-1, 0, 1)[x<1:]
    yrange = (-1, 0, 1)[y<1:]
    return [(x + dx,y + dy) for dx in xrange for dy in yrange if dx or dy]