Python: удаление элемента списка во время итерации по списку

Я повторяю список элементов в Python, делаю на нем какое-то действие, а затем удаляю их, если они удовлетворяют определенным критериям.

for element in somelist:
    do_action(element)
    if check(element):
        remove_element_from_list

Что следует использовать вместо remove_element? Я видел похожие вопросы, но обратите внимание на наличие части do_action, которая должна быть выполнена для всех элементов и, таким образом, устраняет решение использования фильтров.

Ответ 1

Вы всегда можете перебирать копию списка, оставляя за собой право изменять оригинал:

for item in list(somelist):
  ...
  somelist.remove(item)

Ответ 2

Чтобы выполнить эти критерии: измените исходный список на месте, нет экземпляров списка, только один проход, работает, традиционное решение состоит в повторении итерации назад:

for i in xrange(len(somelist) - 1, -1, -1):
    element = somelist[i]
    do_action(element)
    if check(element):
        del somelist[i]

Бонус: не выполняет len(somelist) на каждой итерации. Работает на любой версии Python (по крайней мере, еще в 1.5.2)... s/xrange/range/for 3.X.

Обновление: если вы хотите итерации вперед, это возможно, просто сложнее и уродливее:

i = 0
n = len(somelist)
while i < n:
    element = somelist[i]
    do_action(element)
    if check(element):
        del somelist[i]
        n = n - 1
    else:
        i = i + 1

Ответ 3

Список comp:

results = [x for x in (do_action(element) for element in somelist) if check(element)]

Ответ 4

for element in somelist:
    do_action(element)
somelist[:] = (x for x in somelist if not check(x))

Если вам действительно нужно сделать это за один проход без копирования списка

i=0
while i < len(somelist):
    element = somelist[i] 
    do_action(element)
    if check(element):
        del somelist[i]
    else:
        i+=1

Ответ 5

Вы все равно можете использовать фильтр, переходя к внешней функции, модификацию элемента (итерация только один раз)

def do_the_magic(x):
    do_action(x)
    return check(x)

# you can get a different filtered list
filter(do_the_magic,yourList)

# or have it modified in place (as suggested by Steven Rumbalski, see comment)
yourList[:] = itertools.ifilter(do_the_magic, yourList)

Ответ 6

Другой способ сделать это:

while i<len(your_list):
    if #condition :
        del your_list[i]
    else:
        i+=1

Итак, вы удаляете элементы бок о бок, проверяя

Ответ 7

Вы можете создать генератор, который возвращает все, что не удалено:

def newlist(somelist):
    for element in somelist:
        do_action(element)
        if not check(element):
            yield element

Ответ 8

Почему бы не переписать его как

for element in somelist: 
   do_action(element)  

if check(element): 
    remove_element_from_list

Посмотрите на этот вопрос, как удалить из списка, хотя похоже, что вы уже видели, что Удалить элементы из списка во время итерации

Другой вариант - сделать это, если вы действительно хотите сохранить это же

newlist = [] 
for element in somelist: 
   do_action(element)  

   if not check(element): 
      newlst.append(element)

Ответ 9

Не совсем на месте, но есть идея сделать это:

a = ['a', 'b']

def inplace(a):
    c = []
    while len(a) > 0:
        e = a.pop(0)
        if e == 'b':
            c.append(e)
    a.extend(c)

Вы можете расширить функцию, чтобы вызвать фильтр в состоянии.