为什么此代码返回列表索引错误?

时间:2010-12-21 05:03:33

标签: python indexing

基本上它应该采用一组坐标并返回它的邻居坐标列表。然而,当它到达这里时:

if result[i][0] < 0 or result[i][0] >= board.dimensions:
    result.pop(i)

i为2时,它会给我一个索引错误。我可以设法打印结果[2] [0],但在if语句中它会抛出错误。为什么会这样?

def neighborGen(row,col,board):
    """
    returns lists of coords of neighbors, in order of up, down, left, right
    """

    result = []
    result.append([row-1 , col])
    result.append([row+1 , col])
    result.append([row , col-1])
    result.append([row , col+1])

     #prune off invalid neighbors (such as (0,-1), etc etc)
     for i in range(len(result)): 
        if result[i][0] < 0 or result[i][0] >= board.dimensions:
            result.pop(i)
        if result[i][1] < 0 or result[i][1] >= board.dimensions:
            result.pop(i)

    return result 

7 个答案:

答案 0 :(得分:4)

您可以从列表中迭代索引,然后继续从列表中删除元素。最终你会打到一个不再存在的索引。请使用列表推导来过滤。

result = [entry for entry in result if entry[0] >= 0 and
  entry[0] < board.dimensions and entry[1] >= 0 and
  entry[1] < board.dimensions]

答案 1 :(得分:2)

for循环期间,您弹出的元素会减小result的大小。然而,i仍将从0变为4。

答案 2 :(得分:2)

如果你弹出一个元素,那么它就不再在列表中了 - 但你的索引不会移动,所以它现在指向下一个元素。假设您弹出两个元素...之后您的列表大小为2,但for循环仍将尝试转到4。

答案 3 :(得分:1)

def neighborGen(row,col,board):
    """
    returns lists of coords of neighbors, in order of up, down, left, right
    """

    return [
        x for x in (
            [row-1 , col], [row+1 , col], [row , col-1], [row , col+1]
        ) 
        if x[0] >= 0 and x[0] < board.dimensions and
        x[1] >= 0 and x[1] < board.dimensions
    ]

答案 4 :(得分:1)

使用列表推导删除无效点。例如:

result = [coords for coords in result
          if all(0 <= c < board.dimension for c in coords)]

答案 5 :(得分:0)

正如其他人所说,当您从列表中间删除元素时,其余元素的索引会发生变化。为避免出现问题,您可以处理从最后一个索引到第一个索引的元素:

for i in range(len(result)-1, -1, -1): 
   ...

现在,当删除当前元素时,只有已处理元素的索引才会更改。由于这些元素已经处理过,不需要再次访问,因此它们的索引不再有效无关紧要。

答案 6 :(得分:0)

避免这种板外测试的规范方法是在板的边缘有一个或两行/列的缓冲区。董事会的职位,以及通常的“空”价值,或者哪一方拥有广场的什么类型的作品,一个特殊的“无效”代码。这通常与作为一维数组的电路板表示相结合。

例如,国际象棋将使用大小为120(10列×12行)的数组。你需要一个2的余量以迎合骑士...每一行2行,但你只需要一个垂直边距,因为它可以共享。

E.g。

KNIGHT_DELTAS = (-21, -19, -12, -8, 8, 12, 19, 21)
# I have a knight at "currpos"; what are its options?
for delta in KNIGHT_DELTAS:
    newpos = currpos + delta
    target = board[newpos]
    if target & EMPTY:
        can_move_to(newpos)
    elif target & OTHER_TEAM:
        can_capture(at=newpos, captured_piece=target & PIECE_VALUE)
    else:
        # Either off the board or occupied by MY_TEAM.
        # Notice that we didn't even need to test explicitly for "off the board".
        pass