Неожиданное поведение простого Python3 скрипта (изменение списка в цикле). Почему?

248 просмотра
0
0 Комментариев

У меня есть следующий простейший скрипт

inp = input().split()
print('inp', inp)
l = []
for elem in inp:
    l.append(int(elem))
 
print('initial: ', l)
 
for el in l:
    print(el)
    if el % 2 != 0:
        l.remove(el)
 
print('after removing odd numbers: ', l)

Первый инпут (строка):

1 2 3 4 5 6 7

вывод:

inp ['1', '2', '3', '4', '5', '6', '7']
initial:  [1, 2, 3, 4, 5, 6, 7]
1
3
5
7
after removing odd numbers:  [2, 4, 6]

Второй инпут (строка):

10 8 5 3 1

вывод:

inp ['10', '8', '5', '3', '1']
initial:  [10, 8, 5, 3, 1]
10
8
5
1
after removing odd numbers:  [10, 8, 3]

Скриншот здесь.

1й ввод/вывод

1) Почемы скрипт выводит только нечетные элементы? Он должен выводить все элементы.


2й ввод/вывод

1) Почему в выводе нет числа 3, только 10, 8, 5 и 1?

2) И, следовательно, почему конечный список содержит число 3?

Благодарю!


Добавить комментарий

2 Answers

Python Опубликовано 12.12.2018
0

Вы проходитесь списком по циклу, который меняете. Это плохая идея. Когда вы удаляете текущий элемент в цикле из списка, внутри питона текущим неявно становится следующий элемент. А когда начинается следующая итерация, берётся снова следующий элемент, тем самым один элемент проскакивается.

Покажу наглядно на этом коде:

a = [1, 2, 3, 4, 5]
for x in a:
    a.remove(x)

Первая итерация до удаления — берётся элемент с индексом 0:

[1, 2, 3, 4, 5]
 ^ - текущий элемент

Первая итерация после удаления (обращаю внимание, что значение переменной x никто не поменяет):

[2, 3, 4, 5]
 ^

Упс, мы неявно поменяли текущий элемент. Хотя в переменной x всё ещё содержится единица, по индексу 0 уже находится совсем другой элемент.

Вторая итерация — берётся элемент с индексом 1:

[2, 3, 4, 5]
    ^

Упс! Проскочили.


Как лечить?

Никогда не менять список, по которому проходитесь циклом. Например, сделать его копию и запустить цикл уже по копии:

l_copy = l[:]
for el in l_copy:
    print(el)
    if el % 2 != 0:
        l.remove(el)


Для лучшего понимания работы цикла ещё пример:

a = [0, 0, 0, 0]
i = 1
for x in a:
    a.insert(i, 7)
    print(x)
    i += 1

Этот код отпечатает сперва 0, а потом бесконечно будет выдавать семёрки 🙂

a = [0, 1, 2, 3]
i = 0
for x in a:
    a.insert(i, 7)
    print(x)
    i += 1

А вот так семёрок не будет, а будут бесконечные нули (мы постоянно смещаем его вправо новыми семёрками и он постоянно оказывается следующим элементом по индексу).

Добавить комментарий
0

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

a = [1, 2, 3, 4, 5]
b = [el for el in a if el%2 == 0]
print (b)

Добавить комментарий
Напишите свой ответ на данный вопрос.
Scroll Up