2015-08-28 7 views

ответ

3

Вы не должны изменять содержимое списка во время прохода по ней

Но вы могли бы перебрать копии содержимого списка и изменить его в случае

Код:

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] 
+0

Ваше решение дает одну дополнительную итерацию по списку для каждого элемента, который нужно удалить, и один дополнительный для создания нового списка плюс требуемая память. Просто используйте фильтр, чтобы создать новый список и не беспокоиться об удалении. – metatoaster

+0

@metatoaster согласился просто показать, что OP может сделать это с его одним кодом с небольшими изменениями – The6thSense

+0

@metatoaster добавил фильтр, как вы заявили – The6thSense

6

Никогда не изменяйте список, итерации по нему. Результаты непредсказуемы, как вы видите здесь. Один простой альтернативой является построить новый список:

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] 

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

3

Это не работает, потому что вы изменяете список по мере его итерации, и текущий указатель перемещается мимо одного из 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

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

+0

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

+0

@PeterDeGlopper Я в конечном итоге расширился, когда вы делали этот комментарий, также добавил, что другая ссылка тоже. – metatoaster

+0

Подумайте об этом, если бы OP были готовы терпеть алгоритм 'n^2' (например, что-либо, используя' remove'), самый простой способ сделать это - просто запустить его в бесконечном цикле 'while', который ломается на 'ValueError', когда ничего не соответствует аргументу' remove'. –

5

Рассмотрим этот код:

#!/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 не может обрабатывать список с динамическим размером.

+0

Это еще один хороший способ изменить список на месте. –

Смежные вопросы