Индекс списка 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"]
,
6 ответов
Проблема в том, что range(len(arr) - 1)
возвращает фиксированный объект, который повторяется. Длина массива не пересчитывается каждую итерацию.
Одно из возможных решений - скопировать все ненужные элементы в другой список.
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)
}
Не удаляйте предметы из 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
Вероятно, ошибка связана со вторым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 используют snake-case для имен функций (как я делал выше) вместо camel-case. Кроме того, одним из преимуществ языка Python является то, что он хорошо читается - он может читать почти как на английском. Не стесняйтесь использовать очень описательные имена для ваших переменных и функций. Это облегчает чтение и понимание вашего кода другими программистами, а также облегчает чтение и понимание позже.
Это хорошо описано в Руководстве по стилю PEP-8, которому вы должны стараться следовать, насколько это возможно, при программировании на Python.
Это потому, что вы удаляете элемент из списка, затем он продолжает цикл по списку с необновленным 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