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



在下面的代码中,我尝试查看给定列表的下一项是否与上一项相反(即"北"和"南"或"东"和"西"(。当然,一旦我们到达列表的最后一项,这将引发 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)返回一个迭代的固定对象。数组的长度不会在每次迭代时重新计算。

一种可能的解决方案是将所有您不想"删除"的元素复制到另一个列表中。

在迭代此操作时,不要从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],因为您超过了数组的长度。

发生此错误的原因是您在每次迭代期间循环访问列表并删除元素。通常,修改要迭代的基础对象是危险的,并且无论您使用哪种语言,都会导致有趣的错误。作为一个初级程序员,这是你应该避免的做法,除非你有很好的理由这样做。

正如所建议的那样,创建基础列表的副本并从副本中删除元素而不是要迭代的对象是避免这种情况的好方法。如果这样做,请确保正确执行此操作。

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

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 风格指南很好地涵盖了这一点,在用 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) 
}

最新更新