2

在下面的方法中,我组装了一个元组列表,同时试图确保没有一个值小于零。下面的方法首先获取一个块并使用它来计算相邻块的坐标,增量为 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),从某种意义上说,我离我需要的位置更近了一点,因为它的打印输出中的方法包括我想要删除的两个元组。但当然,这样做的一个缺点是我不再从该列表中删除任何目标元组。

对此的任何帮助将不胜感激,我真的希望我的疏忽不是很明显。顺便说一句,我觉得应该有一种方法来组装这个列表,同时能够放弃删除阶段,这就是我在刚刚解决上面的代码之前开始编写这个方法的方式。谢谢!

4

6 回答 6

3

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

为避免此问题,您可以使用切片遍历列表的副本:

for item in neighbor_list[:]:

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

new_list = [(x, y) for x, y in neighbor_list if x >= 0 and y >= 0]
于 2013-10-28T04:01:05.167 回答
1

您不应该从您正在迭代的列表中删除项目。首先制作列表的副本,然后对其进行迭代。

于 2013-10-28T03:58:42.997 回答
1

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

[item for item in neighbor_list if item[0] >= 0 and item[1] >= 0]
于 2013-10-28T03:59:24.063 回答
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
于 2013-10-28T04:00:15.380 回答
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
于 2013-10-28T03:58:42.903 回答
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]
于 2013-10-28T04:23:45.590 回答