python: индекс списка вне диапазона ошибок при итеративном извлечении элементов

Я написал простую программу на питоне

l=[1,2,3,0,0,1]
for i in range(0,len(l)):
       if l[i]==0:
           l.pop(i)

Это дает мне ошибку «индекс списка вне диапазона» в строке if l[i]==0:

После отладки я смог выяснить, что i увеличивается, а список уменьшается.
Однако у меня есть условие завершения цикла i < len(l). Тогда почему я получаю такую ​​ошибку?


person atv    schedule 25.11.2009    source источник
comment
У меня есть условие завершения цикла i ‹ len(l) Почему вы так говорите? Где в вашем коде вы это видите?   -  person S.Lott    schedule 25.11.2009
comment
@ S. Lott, i in range(0,len()) означает "я дойду до len(l)-1"   -  person atv    schedule 25.11.2009
comment
Еще один совет по Python — вы могли бы просто написать range(len(l)), так как 0 — это начальное значение по умолчанию.   -  person abyx    schedule 25.11.2009
comment
Из PEP 8: Никогда не используйте символы l (строчная буква el), O (заглавная буква oh) или I (заглавная буква глаз) в качестве односимвольных имен переменных. python.org/dev/peps/pep-0008   -  person Stephan202    schedule 25.11.2009
comment
@atv: Что заставляет вас думать, что range(0,len(l)) имеет результат, который меняется при изменении l? Почему вы так думаете? Где ты это прочитал?   -  person S.Lott    schedule 26.11.2009
comment
Возможный дубликат Удалить элементы из списка во время итерации   -  person tripleee    schedule 02.03.2017


Ответы (11)


Вы уменьшаете длину своего списка l по мере его повторения, поэтому, когда вы приближаетесь к концу своих индексов в операторе диапазона, некоторые из этих индексов больше недействительны.

выглядит так, что вы хотите сделать следующее:

l = [x for x in l if x != 0]

который вернет копию l без каких-либо нулевых элементов (эта операция называется понимание списка, кстати). Вы даже можете сократить эту последнюю часть до if x, поскольку ненулевые числа оцениваются как True.

Не существует такой вещи, как условие завершения цикла i < len(l) в том виде, в котором вы написали код, потому что len(l) предварительно вычисляется перед циклом, а не пересчитывается на каждой итерации. Однако вы могли написать это так:

i = 0
while i < len(l):
   if l[i] == 0:
       l.pop(i)
   else:
       i += 1
person Mark Rushakoff    schedule 25.11.2009

Выражение len(l) вычисляется только один раз, в момент вычисления встроенной функции range(). Объект полигона, построенный в это время, не меняется; он не может ничего знать об объекте l.

P.S. l — паршивое имя для значения! Похоже на цифру 1 или заглавную букву I.

person Jonathan Feinberg    schedule 25.11.2009

Вы меняете размер списка, перебирая его, что, вероятно, не то, что вам нужно, и является причиной вашей ошибки.

Изменить: Как уже ответили и прокомментировали другие, понимание списков лучше в качестве первого выбора, особенно в ответ на этот вопрос. По этой причине я предложил это в качестве альтернативы, и, хотя это не лучший ответ, он все же решает проблему.

Итак, в этой заметке вы также можете использовать filter, что позволяет вам вызывать функцию для оценки элементов в списке, которые вам не нужны.

Пример:

>>> l = [1,2,3,0,0,1]
>>> filter(lambda x: x > 0, l)
[1, 2, 3]

Живи и учись. Лучше просто, за исключением случаев, когда вам нужно что-то сложное.

person jathanism    schedule 25.11.2009
comment
Вам даже не нужна лямбда, так как 0 оценивается как False. filter(None, l) - person Steve Losh; 25.11.2009
comment
@Steve Losh - Это то, что мне нравится в ТАК ... Изучение простых маленьких трюков, чтобы сэкономить мне нажатия клавиш в долгосрочной перспективе! Спасибо! - person jathanism; 25.11.2009
comment
-1: Почему вы указываете новичку на этот устаревший способ? Понимание списков теперь является предпочтительным способом сделать это. - person nikow; 25.11.2009
comment
-1 для фильтра или карты. Вы всегда должны использовать понимание списка, если оно будет выполнять свою работу. - person Nick Bastin; 25.11.2009
comment
Вы, ребята, правы, но filter по-прежнему является важной частью инструментария, когда вам нужна более продвинутая оценка. - person jathanism; 27.11.2009

То, что сказал Марк Рушаков, верно, но если вы выполните итерацию в противоположном направлении, можно удалить элементы из списка в также цикл for. Например.,

x = [1,2,3,0,0,1]
for i in range(len(x)-1, -1, -1):
    if x[i] == 0:
        x.pop(i)

Это как высокое здание, которое падает сверху вниз: даже если оно находится в процессе обрушения, вы все равно можете «войти» в него и посетить еще не обрушившиеся этажи.

person Pugsley    schedule 27.02.2016

Я думаю, что лучший способ решить эту проблему:

l = [1, 2, 3, 0, 0, 1]
while 0 in l:
    l.remove(0)

Вместо того, чтобы перебирать список, я удаляю 0 до тех пор, пока в списке не останется 0.

person Community    schedule 26.12.2018

Проблема заключалась в том, что вы пытались изменить список, на который ссылались, в цикле, в котором использовался список len(). Когда вы удаляете элемент из списка, новый len() вычисляется в следующем цикле.

Например, после первого запуска, когда вы удалили (i) с помощью l.pop(i), это произошло успешно, но в следующем цикле длина списка изменилась, поэтому все номера индексов были сдвинуты. В какой-то момент цикл пытается пройти по укороченному списку, выдавая ошибку.

Выполнение этого вне цикла работает, однако было бы лучше создать новый список, сначала объявив пустой список перед циклом, а затем в цикле добавив все, что вы хотите сохранить, в новый список.

Для тех из вас, кто, возможно, столкнулся с той же проблемой.

person StevenSavant    schedule 16.06.2015

Понимание списка приведет вас к решению.

Но правильный способ скопировать объект в Python — это использовать копию модуля Python — Shallow и операции глубокого копирования.

l=[1,2,3,0,0,1]
for i in range(0,len(l)):
   if l[i]==0:
       l.pop(i)

Если вместо этого

import copy
l=[1,2,3,0,0,1]
duplicate_l = copy.copy(l)
for i in range(0,len(l)):
   if l[i]==0:
       m.remove(i)
l = m

Тогда ваш собственный код сработал бы. Но для оптимизации понимание списка — хорошее решение.

person Manish Tripathi    schedule 30.05.2016

Я использую питон 3.3.5. Приведенное выше решение с использованием цикла while не сработало для меня. Даже если я поставлю print (i) после len(l), это выдаст мне ошибку. Я запустил тот же код в командной строке (оболочке) [окно, которое появляется, когда мы запускаем функцию], он работает без ошибок. Что я сделал, так это вычислил len(l) вне функции в основной программе и передал длину в качестве параметра. Это сработало. Python иногда бывает странным.

person Aseem    schedule 06.02.2015

Я думаю, что в большинстве решений здесь говорится о понимании списка, но если вы хотите выполнить удаление на месте и сохранить сложность пространства до O (1); Решение:

i = 0
for j in range(len(arr)):
if (arr[j] != 0):
    arr[i] = arr[j]
    i +=1
arr = arr[:i] 
person Shayan    schedule 19.03.2019

Код:

while True:
        n += 1
        try:
          DATA[n]['message']['text']
        except:
          key = DATA[n-1]['message']['text']
          break

Приставка :

Traceback (most recent call last):
  File "botnet.py", line 82, in <module>
    key =DATA[n-1]['message']['text']
IndexError: list index out of range
person Saleh Pxo    schedule 24.10.2019
comment
Из отзыва: Привет, пожалуйста, не отвечайте только исходным кодом. Постарайтесь дать хорошее описание того, как работает ваше решение. См.: Как написать хороший ответ?. Спасибо - person sɐunıɔןɐqɐp; 24.10.2019

Недавно у меня была похожая проблема, и я обнаружил, что мне нужно уменьшить индекс списка на единицу.

Итак, вместо:

if l[i]==0:

Можешь попробовать:

if l[i-1]==0:

Потому что индексы списка начинаются с 0, а ваш диапазон будет на единицу выше этого.

person Warren Feeney    schedule 06.03.2020
comment
Это не только неправильно, но и решает другую проблему. У OP есть проблема, когда они сами удаляют элементы списка при переборе списка. Кроме того, i начинается с 0 в вопросе ОП. В вашем примере OP начнет итерацию с последнего элемента массива, а затем вернется к первому. - person Joshua Schlichting; 07.03.2020
comment
Попробуйте это (поскольку это комментарий, вы сами должны разобраться с форматированием в своей среде IDE): python l=[1,2,3,0,0,1] for i in range(0,len(l)): print("element:" + str(i - 1)) print(l[i-1]) - person Joshua Schlichting; 07.03.2020