Почему это не работает для цикла? Моя цель - удалить каждые 1
из моего списка.python удалить все записи значения в списке
>>> s=[1,4,1,4,1,4,1,1,0,1]
>>> for i in s:
... if i ==1: s.remove(i)
...
>>> s
[4, 4, 4, 0, 1]
Почему это не работает для цикла? Моя цель - удалить каждые 1
из моего списка.python удалить все записи значения в списке
>>> s=[1,4,1,4,1,4,1,1,0,1]
>>> for i in s:
... if i ==1: s.remove(i)
...
>>> s
[4, 4, 4, 0, 1]
Вы не должны изменять содержимое списка во время прохода по ней
Но вы могли бы перебрать копии содержимого списка и изменить его в случае
Код:
s=[1,4,1,4,1,4,1,1,0,1]
for i in s[:]:
if i ==1: s.remove(i)
print s
Выход:
[4, 4, 4, 0]
Как @metatoaster заявил, вы можете использовать filter
Код:
s=[1,4,1,4,1,4,1,1,0,1]
s=list(filter(lambda x:x !=1,s))
print s
[4, 4, 4, 0]
Вы можете использовать фильтр, чтобы удалить несколько вещей пример
Код:
s=[1,4,1,4,1,4,1,1,0,1,2,3,5,6,7,8,9,10,20]
remove_element=[1,2,3,5,6,7,8,9]
s=list(filter(lambda x:x not in remove_element,s))
print s
[4, 4, 4, 0, 10, 20]
Никогда не изменяйте список, итерации по нему. Результаты непредсказуемы, как вы видите здесь. Один простой альтернативой является построить новый список:
s = [i for i in s if i != 1]
Если по какой-то причине вы абсолютно должны редактировать список на месте, а не строить новый, мой неподготовленный лучший ответ, чтобы пройти через него найти индексы, которые должны быть удалены, а затем обратным ходом этого списка индексов удаления их один за другим:
indices_to_remove = [i for (i, val) in enumerate(s) if val == 1]
for i in reversed(indices_to_remove):
del s[i]
Потому что удаляют элементы из конца списка первого, исходные показатели, вычисляемые остаются в силе. Но обычно я предпочитаю вычислять новый список, если не применяются особые обстоятельства.
Это не работает, потому что вы изменяете список по мере его итерации, и текущий указатель перемещается мимо одного из 1
, с которым вы проверяете. Мы можем проиллюстрировать это:
>>> for i in s:
... print(s)
... if i == 1:
... s.remove(i)
...
[1_, 4, 1, 4, 1, 4, 1, 1, 0, 1]
[4, 1_, 4, 1, 4, 1, 1, 0, 1]
[4, 4, 1_, 4, 1, 1, 0, 1]
[4, 4, 4, 1_, 1, 0, 1]
[4, 4, 4, 1, 0_, 1]
[4, 4, 4, 1, 0, 1_]
Я добавил _
в сравниваемых элемент. Обратите внимание на то, что всего было всего 6 проходов, и один из 1
s фактически перешел от того, что когда-либо смотрел. Это заканчивается тем элементом, который был удален, потому что list.remove
удаляет первое вхождение указанного элемента и является собственной операцией O (n), которая очень быстро получает , когда ваш список становится большим - это O (n) даже если элемент находится в начале, так как он должен копировать каждый отдельный элемент из всего после элемента один элемент вперед, поскольку python list
s больше похожи на массивы типа C, чем Java-связанные списки (если вы хотите использовать связанные списки, используйте collections.deque
). O (n) в конце, потому что он должен итерации по всему списку, чтобы выполнить собственное сравнение. Полученный вами код может привести к худшей сложности выполнения O (n log n), если вы используете remove
.
См Python's data structure time complexity
ответ Петр уже покрыл поколение нового списка, я только отвечать, почему и как исходный код не работает точно.
Только для того, чтобы понять, что поведение языка в этом случае не определено, но это хорошая демонстрация того, как это реализуется в общей реализации C, и как все, что реализует явный итератор на основе индексов, измененная структура данных справится с этим. –
@PeterDeGlopper Я в конечном итоге расширился, когда вы делали этот комментарий, также добавил, что другая ссылка тоже. – metatoaster
Подумайте об этом, если бы OP были готовы терпеть алгоритм 'n^2' (например, что-либо, используя' remove'), самый простой способ сделать это - просто запустить его в бесконечном цикле 'while', который ломается на 'ValueError', когда ничего не соответствует аргументу' remove'. –
Рассмотрим этот код:
#!/usr/bin/env python
s=[1, 4, 1, 4, 1, 4, 1, 1, 0, 1]
list_size=len(s)
i=0
while i!=list_size:
if s[i]==1:
del s[i]
list_size=len(s)
else:
i=i + 1
print s
Результат:
[4, 4, 4, 0]
Для краткости, ваш код получить нежелательный результат из-за «размер» и «индекс позиции» вашего списка меняются каждые раз вы сократить число 1
и ваш код ясно доказан, что for each loop
в Python
не может обрабатывать список с динамическим размером.
Это еще один хороший способ изменить список на месте. –
Ваше решение дает одну дополнительную итерацию по списку для каждого элемента, который нужно удалить, и один дополнительный для создания нового списка плюс требуемая память. Просто используйте фильтр, чтобы создать новый список и не беспокоиться об удалении. – metatoaster
@metatoaster согласился просто показать, что OP может сделать это с его одним кодом с небольшими изменениями – The6thSense
@metatoaster добавил фильтр, как вы заявили – The6thSense