Ответ 1
Вы не можете удалять элементы из списка, итерации по нему. Гораздо проще построить новый список на основе старого:
y = [s for s in x if len(s) == 2]
Возможный дубликат:
Удалить элементы из списка, итерации в Python
Я пытаюсь удалить элемент из списка в python:
x = ["ok", "jj", "uy", "poooo", "fren"]
for item in x:
if len(item) != 2:
print "length of %s is: %s" %(item, len(item))
x.remove(item)
Но он не удаляет элемент "fren"
. Любые идеи?
Вы не можете удалять элементы из списка, итерации по нему. Гораздо проще построить новый список на основе старого:
y = [s for s in x if len(s) == 2]
hymloth и sven отвечают на работу, но они не изменяют список (создайте новый). Если вам нужна модификация объекта, вам нужно назначить срез:
x[:] = [value for value in x if len(value)==2]
Однако для больших списков, в которых вам нужно удалить несколько элементов, это потребляемая память, но она работает в O (n).
glglgl answer страдает сложностью O (n²), потому что list.remove
- O (n).
В зависимости от структуры ваших данных вы можете предпочесть отметить индексы элементов для удаления и использовать del
для удаления по индексу:
to_remove = [i for i, val in enumerate(x) if len(val)==2]
for index in reversed(to_remove): # start at the end to avoid recomputing offsets
del x[index]
Теперь del x[i]
также O (n), потому что вам нужно скопировать все элементы после индекса i
(список - это вектор), поэтому вам нужно будет протестировать это против ваших данных. Тем не менее это должно быть быстрее, чем использование remove
, потому что вы не оплачиваете стоимость этапа поиска для удаления, а стоимость копирования в обоих случаях одинакова.
[править] Очень хорошая версия на месте, O (n) с ограниченными требованиями к памяти, любезно предоставлена @Sven Marnach. Он использует itertools.compress
, который был введен в python 2.7:
from itertools import compress
selectors = (len(s) == 2 for s in x)
for i, s in enumerate(compress(x, selectors)): # enumerate elements of length 2
x[i] = s # move found element to beginning of the list, without resizing
del x[i+1:] # trim the end of the list
x = [i for i in x if len(i)==2]
Это связано с тем, что при делеции итерация пропускает один элемент, поскольку он работает только для индекса.
Обходной путь может быть:
x = ["ok", "jj", "uy", "poooo", "fren"]
for item in x[:]: # make a copy of x
if len(item) != 2:
print "length of %s is: %s" %(item, len(item))
x.remove(item)
Уже упомянутый подход к пониманию списка, вероятно, лучший выбор. Но если вы абсолютно хотите сделать это на месте (например, если x
действительно велико), здесь один из способов:
x = ["ok", "jj", "uy", "poooo", "fren"]
index=0
while index < len(x):
if len(x[index]) != 2:
print "length of %s is: %s" %(x[index], len(x[index]))
del x[index]
continue
index+=1