Python 列表索引超出范围,即使在分隔索引之后

Python list index out of range, even after delimiting the indexes

在下面的代码中,我尝试查看给定列表的下一项是否与前一项相反(即 "North" & "South" 或 "East" & "West").当然,一旦我们到达列表的最后一项,这将引发 IndexError。 但是,我仔细地划定了 for 循环的界限,以便它在到达最后一个索引之前停止。

def dirReduc(arr):

for i in range(len(arr)-1):

    if arr[i] == "NORTH" and arr[i+1] == "SOUTH":
        arr.remove("NORTH"), arr.remove("SOUTH")

    elif arr[i] == "SOUTH" and arr[i+1] == "NORTH":
        arr.remove("SOUTH"), arr.remove("NORTH")

    elif arr[i] == "WEST" and arr[i+1] == "EAST":
        arr.remove("WEST"), arr.remove("EAST")

    elif arr[i] == "EAST" and arr[i+1] == "WEST":
        arr.remove("EAST"), arr.remove("WEST")

return arr

任何人都可以向我解释为什么这仍然引发 IndexError: list out of range 吗?

这是一个示例输入: ["NORTH", "SOUTH", "SOUTH", "EAST", "WEST", "NORTH", "WEST"].

问题是 range(len(arr) - 1) returns 迭代的固定对象。每次迭代都不会重新计算数组的长度。

一个可能的解决方案是将所有不需要的元素 "removed" 复制到另一个列表。

不要在迭代时从 list 中删除项目(这会导致您的错误)。你可以试试这个主意:

def dirReduc(arr):
    expected_list = arr
    for i in range(len(arr) - 1):

        if arr[i] == "NORTH" and arr[i + 1] == "SOUTH":
            expected_list.remove("NORTH"), expected_list.remove("SOUTH")

        elif arr[i] == "SOUTH" and arr[i + 1] == "NORTH":
            expected_list.remove("SOUTH"), expected_list.remove("NORTH")

        elif arr[i] == "WEST" and arr[i + 1] == "EAST":
            expected_list.remove("WEST"), expected_list.remove("EAST")

        elif arr[i] == "EAST" and arr[i + 1] == "WEST":
            expected_list.remove("EAST"), expected_list.remove("WEST")

    return expected_list

这是因为你从列表中删除元素,然后它继续循环遍历未更新的列表len/range。 为了避免这种情况,可以使用这种丑陋的方法:

def dirReduc(arr):

    for i in range(len(arr)-1):
        if i >= len(arr):
            break
        if arr[i] == "NORTH" and arr[i+1] == "SOUTH":
            arr.remove("NORTH"), arr.remove("SOUTH")

        elif arr[i] == "SOUTH" and arr[i+1] == "NORTH":
            arr.remove("SOUTH"), arr.remove("NORTH")

        elif arr[i] == "WEST" and arr[i+1] == "EAST":
            arr.remove("WEST"), arr.remove("EAST")

        elif arr[i] == "EAST" and arr[i+1] == "WEST":
            arr.remove("EAST"), arr.remove("WEST")

    return arr

可能错误是由于第二个“elif”引起的,因为如果您正在阅读的 arr[i] 匹配数组的最后一个元素,则您无法考虑下一个的条件元素 arr[i + 1],因为您超出了数组的长度。

发生错误是因为您正在遍历列表并在每次迭代中删除元素。一般来说,修改您正在迭代的底层对象是危险的,并且无论您使用何种语言工作都会导致有趣的错误。作为初学者,除非您有充分的理由这样做,否则您应该避免这种做法.

正如所建议的那样,创建底层列表的副本并从副本中删除元素而不是您正在迭代的对象是避免这种情况的好方法。如果你这样做,make sure you do it correctly.

作为另一种可能的解决方案,考虑使用字典将每个方向映射到其相反方向:

opposite = { "NORTH": "SOUTH", "SOUTH": "NORTH", "EAST": "WEST", "WEST": "EAST" } 

现在当你遍历列表时,你可以

def consolidate_directions(direction_list):
    directions = []
    # iterating over enumerate(iterable) is like iterating 
    # over iterable except it gives you access to both the current 
    # iteration count and the current item being processed on each iteration
    for i, direction in enumerate(direction_list):
        # this is a trick to avoid out of bounds error when checking for
        # the last element of the list. % is the modulus operator that returns 
        # 0 if the right hand side divides the left hand side evenly. In this 
        # case that would signify the first element of the list, meaning the 
        # current element is the last 
        last_index = (i - 1) % len(direction_list)
        next_index = (i + 1) % len(direction_list)
        if next_index == 0:
            return directions
        else:
            if not (direction_list[next_index] == opposite[direction]) \
             and not (direction_list[last_index] == opposite[direction]):
                directions.append(direction)
    return directions

更一般的反馈:大多数 Python 程序员使用蛇形大小写作为函数名称(就像我上面所做的那样)而不是驼峰式大小写。此外,Python 作为一种语言的好处之一是它具有很高的可读性——它几乎可以像英语一样阅读。随意为您的变量和函数使用高度描述性的名称。这使您的代码更容易被其他程序员阅读和理解,并且您自己以后也更容易阅读和理解。

这在 PEP-8 Style Guide 中有很好的介绍,您在 Python 中编程时应该尽可能地遵循它。

def dirReduc(arr):
    if len(arr)-1>0:
       num=  len(arr)-1
       for i in range(num):
           if arr[i] == "NORTH" and arr[i+1] == "SOUTH":
               arr[i]="error", arr[i+1]="error"

           elif arr[i] == "SOUTH" and arr[i+1] == "NORTH":
               arr[i]="error", arr[i+1]="error"
           elif arr[i] == "WEST" and arr[i+1] == "EAST":
               arr[i]="error", arr[i+1]="error"
           elif arr[i] == "EAST" and arr[i+1] == "EAST":
               arr[i]="error", arr[i+1]="error"
    return arr

def main(){
    arr=["EAST","EAST"]#just a example
    arrbuff=[]
    arrbuff.append(dirReduc(arr))#arrbuff is ["error","error"]
    newArr=[];#all correct direction
    for i in range(len(arrbuff)):
        if arrbuff[i] == "error" :
            print("what the error u set hahaha")
        else:
            newArr.append(arrbuff) 
}