Почему не был удален последний номер в этом списке? - PullRequest
0 голосов
/ 29 марта 2020

Это моя Python программа:

def highest_even(li):
  for num in li:
    if num % 2 != 0:
      li.remove(num)
  return li

print(highest_even([10,2,3,4,5,80,15,99]))

И вывод:

[10, 2, 4, 80, 99]

Я хочу знать, почему 99 не было удалено.

Спасибо.

Ответы [ 8 ]

1 голос
/ 29 марта 2020

Как правило, плохая идея модифицировать список, по которому вы перебираете, могут произойти всевозможные странные вещи. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *. Когда вы удаляете элемент, все остальные сдвигаются «влево» в списке, но Python все еще продвигает позицию. Это означает, что если у вас есть два нечетных числа в строке (например, 15 и 99) (a) , удаление 15 перемещает 99 влево (туда, где 15 был), но следующая итерация будет искать, где 99 был до смещения, а не там, где он сейчас.

Например, рассмотрим список [1, 3, 6, 8], это шаги, которые Python предпримет:

List          Pos  newList    newPos  comment
----          ---  -------    ------  -------
[1, 3, 6, 8]   0   [3, 6, 8]     1    Odd 1, delete, advance.
[3, 6, 8]      1   [3, 6, 8]     2    Even 6, leave, advance.
[3, 6, 8]      2   [3, 6, 8]     3    Even 8, leave, advance.
[3, 6, 8]      3                      iteration finished.

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

Что касается решения: если, как ваш код предполагает, что вы просто хотите использовать четные числа в списке, вы можете использовать гораздо более сжатое (и Pythoni c) понимание списка (нет необходимости даже для этой функции):

myList = [10, 2, 3, 4, 5, 80, 15, 99]
evens = [item for item in myList if item % 2 == 0]
# gives [10, 2, 4, 80]

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

biggestEven = max([item for item in myList if item % 2 == 0])
# gives 80

(a) Ваша проблема на самом деле не имеет ничего общего с тем фактом, что 99 i s в конце списка, любое последовательных нечетных чисел в любом месте списка может вызвать такую ​​же проблему.

1 голос
/ 29 марта 2020

не изменяйте список, который вы повторяете в

, который вы можете скопировать перед повторением в

def highest_even(li):
  for num in li.copy():
    if num % 2 != 0:
      li.remove(num)
  return li

print(highest_even([10,2,3,4,5,80,15,99]))

Выполнение:

[10, 2, 4, 80]
0 голосов
/ 29 марта 2020

Вы не должны обновлять список, просматривая его. Но вы можете заставить его работать, возвращаясь назад, или вы будете срезать ветку дерева, сидя на нем.

li = [10,2,3,4,5,80,15,99]

for i in range(len(li) - 1, -1, -1):
    if (i%2 != 0 ):
        del li[i]
print(li)
0 голосов
/ 29 марта 2020

Не следует перебирать список и удалять элементы этого списка. Поскольку индекс используется итеративно в al oop. 0- 10 1- 2 2- 3 3- 4 4- 5 5- 80 6- 15 7- 99 Как и при удалении элементов из списка, следующий элемент пропускается. В вашем примере для индексов 0 и 1 ничего не меняется. Но когда index = 3 и согласно условию этот элемент удаляется и список обновляется до [10,2,4,5,80,15,99].

После индекса = 3 следующий индекс равен 4 и li[4] equals 5 and not 4. И ваше состояние даже не проверено на элемент 4. Просто оказалось, что оно было правильным. Наличие некоторого нечетного вместо 4 снова даст вам неправильный вывод. То же самое имеет место с последним элементом 99. Так как предыдущий элемент 15 или index = 6 удален, длина списка уменьшена на 1, и она не l oop для index = 4, поскольку индекс достиг своего максимального значения обновленного списка 5 (после удаления 3,5 и 15).

0 голосов
/ 29 марта 2020

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

Если вы печатаете li и num сразу после for num in li:, вы ' Вы увидите, что после удаления элемента из списка следующий элемент пропускается, а это означает, что индексированный элемент перемещается вперед, то же самое происходит с 99 элементом.

Вы можете проверить это здесь.

def highest_even(li):
  for num in li:
    print(li, num)
    if num % 2 != 0:
      li.remove(num)
return li

дает вывод:

In [3]: highest_even([10,2,3,4,5,80,15,99])
([10, 2, 3, 4, 5, 80, 15, 99], 10)
([10, 2, 3, 4, 5, 80, 15, 99], 2)
([10, 2, 3, 4, 5, 80, 15, 99], 3)
([10, 2, 4, 5, 80, 15, 99], 5)
([10, 2, 4, 80, 15, 99], 15)
Out[3]: [10, 2, 4, 80, 99]
0 голосов
/ 29 марта 2020

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

for i in range len(li):
0 голосов
/ 29 марта 2020

это из-за того, что вы перебирали список при редактировании.

only_even = []
for n in lst:
    if not n % 2:
       only_even.append(n)

другие методы

only_even = [n for n in lst if not n % 2]
only_even = list(filter(lambda x: not n % 2, lst))
0 голосов
/ 29 марта 2020

Как отмечают многие комментарии: небезопасно (или, по крайней мере, оно представляет какое-то неожиданное поведение) изменять список при его итерации по нему. Обычное исправление для списков, которые не являются гигантскими, заключается в простом копировании списка, когда вы go повторяете его.

for num in li[:]:
   # everything as before

Этот синтаксис небольшого фрагмента заставляет Python взять список li создайте новый список всего его содержимого и выполните итерацию по нему. Теперь, поскольку вы удаляете вещи из li, но перебираете копию li, созданную путем нарезки, нет проблем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...