Почему при удалении элемента из списка в цикле for, пропускается след. элемент списка?
При удалении элемента в цикле for с помощью функции remove или pop почему то пропускается след. элемент списка.
Пример:
cards = [1, 2, 3, 4, 5]
for c in cards:
if c == 3:
cards.remove(c)
print(c)
print(cards)
Результат:
1
2
3
5
[1, 2, 4, 5]
В выводе видно что не печатается 4, интересно почему? а в конечном списке он есть.
Ответы (3 шт):
Потому что удаление элемента сдвигает все последующие элементы списка.
Для наглядности, заменим ваши 12345 на ABCDE.
- Вот был список
ABCDE. - Вот у вас идет цикл на 3й итерации вы на элементе
C, и вы решили его удалить. Массив сталABDE. - В следующей итерации, вы уже на 4м элементе - смотрим, это элемент
E. АDполучается "пропущен", действительно.
У вас же еще сложнее - вы храните текущий элемент в переменной c. То что вы его удаляете из списка, не удаляет его из переменной. Получается, что вы элемент из списка удалили, но все равно напечатали, а следующий "пропустили".
Распространённая ошибка среди новичков. Дело в том, что что когда вы итерируетесь с начала списка, и удаляя элементы по очереди все элементы сдвигаются влево, т.к. всегда индексы должны идти по порядку. Для наглядности простой пример:
lst = [i+1 for i in range(10)] # просто заполняет список
for i in range(len(lst)):
print(f"index: {i}")
print(lst)
if lst[i]%2==0:
lst.pop(i)
В коде мы бежимся по списку и удаляем каждый чётный элемент в списке, а для удобства так же выводим индекс элемента который будем проверять(я в ручном режиме для простоты понимания добавил стрелочку указывая на какой элемент сейчас "смотрит" программа).
index: 0
v
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
index: 1
v
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
index: 2
v
[1, 3, 4, 5, 6, 7, 8, 9, 10]
index: 3
v
[1, 3, 5, 6, 7, 8, 9, 10]
index: 4
v
[1, 3, 5, 7, 8, 9, 10]
index: 5
v
[1, 3, 5, 7, 9, 10]
index: 6
v
[1, 3, 5, 7, 9]
IndexError: list index out of range
В конце при таком раскладе мы выйдем за пределы списка и словим ошибку. Если вам необходимо бороться с такого рода ошибкой попробуйте итерироваться наоборот - с конца списка, тогда все элементы не будут сдвигаться, а значит и ошибки не будет. Однако так же стоит заметить что проблема может возникнуть из-за неправильной постановки задачи, например число 3 можно удалить напрямую не проходя по всему списку.
cards = [1, 2, 3, 4, 5]
for c in cards[::-1]: # реверс списка срезами
if c == 3:
cards.remove(c)
print(c)
print(cards)
Вывод программы:
5
4
3
2
1
[1, 2, 4, 5]
Проблему решил с помощью копии списка (очень уж надо было удалить в цикле):
cards = [1, 2, 3, 4, 5]
cards_new = cards.copy()
for c in cards:
cards = cards_new
if c == 3:
cards_new.remove(c)
print(c)
1
2
3
4
5
[1, 2, 4, 5]
print(cards)