Как удалить элементы из списка во время итерации?

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

for tup in somelist:
    if determine(tup):
         code_to_remove_tup

Что следует использовать вместо code_to_remove_tup? Я не могу понять, как удалить элемент таким образом.

Ответ 1

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

somelist = [x for x in somelist if not determine(x)]

Или, назначив срезу somelist[:], вы можете изменить существующий список, чтобы содержать только те элементы, которые вы хотите:

somelist[:] = [x for x in somelist if not determine(x)]

Этот подход может быть полезен, если есть другие ссылки на somelist, которые должны отражать изменения.

Вместо понимания вы также можете использовать itertools. В Python 2:

from itertools import ifilterfalse
somelist[:] = ifilterfalse(determine, somelist)

Или в Python 3:

from itertools import filterfalse
somelist[:] = filterfalse(determine, somelist)

Ответ 2

Ответы, предполагающие понимание списка, почти верны - за исключением того, что они создают совершенно новый список и затем дают ему то же имя, что и старый список, они НЕ изменяют старый список на месте. Это отличается от того, что вы будете делать выборочным удалением, как в предложении @Lennart, - это быстрее, но если к вашему списку обращаются по нескольким ссылкам, тот факт, что вы просто повторно устанавливаете одну из ссылок и НЕ изменяете объект списка само по себе может привести к тонким, катастрофическим ошибкам.

К счастью, очень легко получить как скорость понимания списка, так и требуемую семантику изменения на месте - просто код:

somelist[:] = [tup for tup in somelist if determine(tup)]

Обратите внимание на небольшую разницу с другими ответами: этот НЕ присваивается пустому имени - он присваивает фрагменту списка, который просто является целым списком, тем самым заменяя содержимое списка в том же объекте списка Python, а не просто перезаписывая одну ссылку (из предыдущего объекта списка в новый объект списка), как и другие ответы.

Ответ 3

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

Например (зависит от типа списка):

for tup in somelist[:]:
    etc....

Пример:

>>> somelist = range(10)
>>> for x in somelist:
...     somelist.remove(x)
>>> somelist
[1, 3, 5, 7, 9]

>>> somelist = range(10)
>>> for x in somelist[:]:
...     somelist.remove(x)
>>> somelist
[]

Ответ 4

for i in range(len(somelist) - 1, -1, -1):
    if some_condition(somelist, i):
        del somelist[i]

Вам нужно идти назад, иначе это немного похоже на распиливание ветки дерева, на которой вы сидите :-)

Пользователи Python 2: замените range на xrange чтобы избежать создания жесткого списка

Ответ 5

Лучшим подходом для такого примера будет понимание списка

somelist = [tup for tup in somelist if determine(tup)]

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

newlist = []
for tup in somelist:
    # lots of code here, possibly setting things up for calling determine
    if determine(tup):
        newlist.append(tup)
somelist = newlist

Копирование списка с помощью remove может сделать ваш код немного чище, как описано в одном из ответов ниже. Вы не должны делать этого для чрезвычайно больших списков, поскольку это включает в себя первое копирование всего списка, а также выполнение операции O(n) remove для каждого удаляемого элемента, что делает этот алгоритм O(n^2).

for tup in somelist[:]:
    # lots of code here, possibly setting things up for calling determine
    if determine(tup):
        newlist.append(tup)

Ответ 6

Официальное руководство по Python 2 4.2. "для заявлений"

https://docs.python.org/2/tutorial/controlflow.html#for-statements

Эта часть документов проясняет, что:

  • вам нужно сделать копию итеративного списка, чтобы изменить его
  • один из способов сделать это с помощью обозначения среза [:]

Если вам нужно изменить последовательность, которую вы повторяете во время цикла (например, для дублирования выбранных элементов), рекомендуется сначала сделать копию. Итерация по последовательности неявно делает копию. Обозначение среза делает это особенно удобным:

>>> words = ['cat', 'window', 'defenestrate']
>>> for w in words[:]:  # Loop over a slice copy of the entire list.
...     if len(w) > 6:
...         words.insert(0, w)
...
>>> words
['defenestrate', 'cat', 'window', 'defenestrate']

Документация по Python 2 7.3. "За выражение"

https://docs.python.org/2/reference/compound_stmts.html#for

Эта часть документов еще раз говорит о том, что вы должны сделать копию, и приводит фактический пример удаления:

Примечание: есть тонкость, когда последовательность модифицируется циклом (это может происходить только для изменяемых последовательностей, то есть списков). Внутренний счетчик используется для отслеживания того, какой элемент используется следующим, и он увеличивается на каждой итерации. Когда этот счетчик достигнет длины последовательности, цикл завершается. Это означает, что если набор удаляет текущий (или предыдущий) элемент из последовательности, следующий элемент будет пропущен (поскольку он получает индекс текущего элемента, который уже был обработан). Аналогично, если набор вставляет элемент в последовательность перед текущим элементом, текущий элемент будет обработан снова в следующий раз в цикле. Это может привести к неприятным ошибкам, которых можно избежать, сделав временную копию с использованием фрагмента всей последовательности, например,

for x in a[:]:
    if x < 0: a.remove(x)

Однако я не согласен с этой реализацией, поскольку .remove() должен перебирать весь список, чтобы найти значение.

Лучшие обходные пути

Или:

  • начать новый массив с нуля, и .append() обратно в конце: fooobar.com/questions/13465/...

    Это экономит время, но экономит меньше места, поскольку сохраняет копию массива во время итерации.

  • используйте del с индексом: fooobar.com/questions/13465/...

    Это более экономно, так как распределяет копию массива, но менее эффективно по времени, поскольку списки CPython реализованы с помощью динамических массивов.

    Это означает, что удаление предмета требует сдвига всех следующих предметов назад на один, что является O (N).

Как правило, вы просто хотите использовать более быстрый параметр .append() по умолчанию, если только память не представляет большой проблемы.

Мог ли Python сделать это лучше?

Похоже, что этот конкретный Python API может быть улучшен. Сравните его, например, с его Java-аналогом ListIterator, который четко показывает, что вы не можете изменять итерируемый список, кроме как с помощью самого итератора, и дает вам эффективные способы сделать это без копирования списка.

Возможно, основное обоснование заключается в том, что списки Python предполагаются с поддержкой динамического массива, и поэтому любой тип удаления будет в любом случае неэффективным по времени, в то время как Java имеет более приятную иерархию интерфейса с реализациями ArrayList и LinkedList ListIterator.

Похоже, в Python stdlib нет явного связанного типа списка: Python Linked List

Ответ 7

Для тех, кто любит функциональное программирование:

somelist[:] = filter(lambda tup: not determine(tup), somelist)

или

from itertools import ifilterfalse
somelist[:] = list(ifilterfalse(determine, somelist))

Ответ 8

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

array = [lots of stuff]
arraySize = len(array)
i = 0
while i < arraySize:
    if someTest(array[i]):
        del array[i]
        arraySize -= 1
    else:
        i += 1

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

Ответ 9

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

так:

for item in originalList:
   if (item != badValue):
        newList.append(item)

и во избежание повторного кодирования всего проекта с новым именем списка:

originalList[:] = newList

Заметьте, из документации Python:

copy.copy(х) Верните неглубокую копию x.

copy.deepcopy(х) Верните глубокую копию x.

Ответ 10

Этот ответ был первоначально написан в ответ на вопрос, который с тех пор был отмечен как дубликат: Удаление координат из списка на python

В коде есть две проблемы:

1) При использовании remove() вы пытаетесь удалить целые числа, тогда как вам нужно удалить кортеж.

2) Цикл for пропустит элементы в вашем списке.

Пропустим то, что происходит, когда мы выполняем ваш код:

>>> L1 = [(1,2), (5,6), (-1,-2), (1,-2)]
>>> for (a,b) in L1:
...   if a < 0 or b < 0:
...     L1.remove(a,b)
... 
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
TypeError: remove() takes exactly one argument (2 given)

Первая проблема заключается в том, что вы передаете "a" и "b" для удаления(), но remove() принимает только один аргумент. Итак, как мы можем заставить remove() работать с вашим списком? Нам нужно выяснить, что представляет собой каждый элемент вашего списка. В этом случае каждый из них является кортежем. Чтобы увидеть это, разрешите доступ к одному элементу списка (индексирование начинается с 0):

>>> L1[1]
(5, 6)
>>> type(L1[1])
<type 'tuple'>

Ага! Каждый элемент L1 на самом деле является кортежем. Итак, что нам нужно передать remove(). Кортежи в python очень просты, они просто создаются путем включения значений в круглые скобки. "a, b" не является кортежем, но "(a, b)" является кортежем. Поэтому мы модифицируем ваш код и запускаем его снова:

# The remove line now includes an extra "()" to make a tuple out of "a,b"
L1.remove((a,b))

Этот код запускается без каких-либо ошибок, но посмотрите на список, который он выдает:

L1 is now: [(1, 2), (5, 6), (1, -2)]

Почему (1, -2) все еще в вашем списке? Оказывается, изменение списка при использовании цикла для итерации по нему - очень плохая идея без особой осторожности. Причина, по которой (1, -2) остается в списке, состоит в том, что расположение каждого элемента в списке изменилось между итерациями цикла for. Давайте посмотрим, что произойдет, если мы напишем приведенный выше код более длинным списком:

L1 = [(1,2),(5,6),(-1,-2),(1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
### Outputs:
L1 is now: [(1, 2), (5, 6), (1, -2), (3, 4), (5, 7), (2, 1), (5, -1), (0, 6)]

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

Самое интуитивное решение - скопировать список, затем перебрать исходный список и только изменить копию. Вы можете попробовать сделать это следующим образом:

L2 = L1
for (a,b) in L1:
    if a < 0 or b < 0 :
        L2.remove((a,b))
# Now, remove the original copy of L1 and replace with L2
print L2 is L1
del L1
L1 = L2; del L2
print ("L1 is now: ", L1)

Однако выход будет идентичен предыдущему:

'L1 is now: ', [(1, 2), (5, 6), (1, -2), (3, 4), (5, 7), (2, 1), (5, -1), (0, 6)]

Это потому, что когда мы создали L2, python фактически не создавал новый объект. Вместо этого он просто ссылался на L2 на тот же объект, что и на L1. Мы можем проверить это с помощью "is", который отличается от просто "равно" (==).

>>> L2=L1
>>> L1 is L2
True

Мы можем сделать истинную копию с помощью copy.copy(). Затем все работает так, как ожидалось:

import copy
L1 = [(1,2), (5,6),(-1,-2), (1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
L2 = copy.copy(L1)
for (a,b) in L1:
    if a < 0 or b < 0 :
        L2.remove((a,b))
# Now, remove the original copy of L1 and replace with L2
del L1
L1 = L2; del L2
>>> L1 is now: [(1, 2), (5, 6), (3, 4), (5, 7), (2, 1), (0, 6)]

Наконец, есть одно более чистое решение, чем создание совершенно новой копии L1. Функция reverse():

L1 = [(1,2), (5,6),(-1,-2), (1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
for (a,b) in reversed(L1):
    if a < 0 or b < 0 :
        L1.remove((a,b))
print ("L1 is now: ", L1)
>>> L1 is now: [(1, 2), (5, 6), (3, 4), (5, 7), (2, 1), (0, 6)]

К сожалению, я не могу адекватно описать, как работает reverse(). Он возвращает объект "listreverseiterator", когда ему передается список. Для практических целей вы можете думать о нем как о создании обратной копии своих аргументов. Это рекомендуемое мной решение.

Ответ 11

Возможно, вы захотите использовать filter(), доступный как встроенный.

Подробнее здесь проверить

Ответ 12

Если вы хотите сделать что-либо еще во время итерации, может быть полезно получить как индекс (который гарантирует вам возможность ссылаться на него, например, если у вас есть список dicts), так и фактическое содержимое списка.

inlist = [{'field1':10, 'field2':20}, {'field1':30, 'field2':15}]    
for idx, i in enumerate(inlist):
    do some stuff with i['field1']
    if somecondition:
        xlist.append(idx)
for i in reversed(xlist): del inlist[i]

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

Ответ 13

Большинство ответов здесь требуют, чтобы вы создали копию списка. У меня был прецедент, где список был довольно длинным (110 тыс. Пунктов), и было разумнее продолжать сокращать список.

Прежде всего, вам нужно будет заменить цикл foreach на цикл while,

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

Значение i не изменяется в блоке if, потому что вы захотите получить значение нового элемента ОТ ТОГО УКАЗАТЕЛЯ, как только старый элемент будет удален.

Ответ 14

Вы можете попробовать for-looping в обратном порядке, поэтому для some_list вы сделаете что-то вроде:

list_len = len(some_list)
for i in range(list_len):
    reverse_i = list_len - 1 - i
    cur = some_list[reverse_i]

    # some logic with cur element

    if some_condition:
        some_list.pop(reverse_i)

Таким образом, индекс выровнен и не пострадает от обновлений списка (независимо от того, вы или нет).

Ответ 15

Одно из возможных решений, полезно, если вы хотите не только удалить некоторые вещи, но и сделать что-то со всеми элементами в одном цикле:

alist = ['good', 'bad', 'good', 'bad', 'good']
i = 0
for x in alist[:]:
    if x == 'bad':
        alist.pop(i)
        i -= 1
    # do something cool with x or just print x
    print(x)
    i += 1

Ответ 16

Мне нужно было сделать что-то подобное, и в моем случае проблема была в памяти - мне нужно было объединить несколько объектов набора данных в список, после того, как с ними что-то сработало, как новый объект и нужно было избавиться от каждой записи. сливалось воедино, чтобы не дублировать их и не взрывать память. В моем случае наличие объектов в словаре вместо списка работало нормально:

`` `

k = range(5)
v = ['a','b','c','d','e']
d = {key:val for key,val in zip(k, v)}

print d
for i in range(5):
    print d[i]
    d.pop(i)
print d

`` `

Ответ 17

TL;DR:

Я написал библиотеку, которая позволяет это сделать:

from fluidIter import FluidIterable
fSomeList = FluidIterable(someList)  
for tup in fSomeList:
    if determine(tup):
        # remove 'tup' without "breaking" the iteration
        fSomeList.remove(tup)
        # tup has also been removed from 'someList'
        # as well as 'fSomeList'

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

Должен работать во всех изменяемых последовательностях, а не только в списках.


Полный ответ:

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

Решение следует из этого ответа (для связанного вопроса) с senderle. Это объясняет, как обновляется индекс массива при повторении через список, который был изменен. Нижеприведенное решение предназначено для правильной отслеживания индекса массива, даже если список изменен.

Скачайте fluidIter.py из здесь https://github.com/alanbacon/FluidIterator, это всего лишь один файл, поэтому не нужно устанавливать git. Нет инсталлятора, поэтому вам нужно убедиться, что файл находится на пути python. Код написан для python 3 и не проверен на python 2.

from fluidIter import FluidIterable
l = [0,1,2,3,4,5,6,7,8]  
fluidL = FluidIterable(l)                       
for i in fluidL:
    print('initial state of list on this iteration: ' + str(fluidL)) 
    print('current iteration value: ' + str(i))
    print('popped value: ' + str(fluidL.pop(2)))
    print(' ')

print('Final List Value: ' + str(l))

Это приведет к следующему выводу:

initial state of list on this iteration: [0, 1, 2, 3, 4, 5, 6, 7, 8]
current iteration value: 0
popped value: 2

initial state of list on this iteration: [0, 1, 3, 4, 5, 6, 7, 8]
current iteration value: 1
popped value: 3

initial state of list on this iteration: [0, 1, 4, 5, 6, 7, 8]
current iteration value: 4
popped value: 4

initial state of list on this iteration: [0, 1, 5, 6, 7, 8]
current iteration value: 5
popped value: 5

initial state of list on this iteration: [0, 1, 6, 7, 8]
current iteration value: 6
popped value: 6

initial state of list on this iteration: [0, 1, 7, 8]
current iteration value: 7
popped value: 7

initial state of list on this iteration: [0, 1, 8]
current iteration value: 8
popped value: 8

Final List Value: [0, 1]

Выше мы использовали метод pop для объекта списка текучей среды. Также применяются другие обычные итерационные методы, такие как del fluidL[i], .remove, .insert, .append, .extend. Список также может быть изменен с использованием срезов (sort и reverse методы не реализованы).

Единственное условие состоит в том, что вы должны только модифицировать список на месте, если в любой точке fluidL или l были переназначены другой объект списка, код не будет работать. Исходный объект fluidL все равно будет использоваться циклом for, но не будет изменен для нас.

то есть.

fluidL[2] = 'a'   # is OK
fluidL = [0, 1, 'a', 3, 4, 5, 6, 7, 8]  # is not OK

Если мы хотим получить доступ к текущему значению индекса, мы не можем использовать перечисление, так как это только подсчитывает, сколько раз цикл for был запущен. Вместо этого мы будем использовать объект итератора напрямую.

fluidArr = FluidIterable([0,1,2,3])
# get iterator first so can query the current index
fluidArrIter = fluidArr.__iter__()
for i, v in enumerate(fluidArrIter):
    print('enum: ', i)
    print('current val: ', v)
    print('current ind: ', fluidArrIter.currentIndex)
    print(fluidArr)
    fluidArr.insert(0,'a')
    print(' ')

print('Final List Value: ' + str(fluidArr))

В результате вы получите следующее:

enum:  0
current val:  0
current ind:  0
[0, 1, 2, 3]

enum:  1
current val:  1
current ind:  2
['a', 0, 1, 2, 3]

enum:  2
current val:  2
current ind:  4
['a', 'a', 0, 1, 2, 3]

enum:  3
current val:  3
current ind:  6
['a', 'a', 'a', 0, 1, 2, 3]

Final List Value: ['a', 'a', 'a', 'a', 0, 1, 2, 3]

Класс FluidIterable просто предоставляет оболочку для исходного объекта списка. К исходному объекту можно обращаться как к свойству жидкого объекта:

originalList = fluidArr.fixedIterable

Дополнительные примеры/тесты можно найти в разделе if __name__ is "__main__": внизу fluidIter.py. Это стоит посмотреть, потому что они объясняют, что происходит в разных ситуациях. Например: Замена больших разделов списка с помощью среза. Или использование (и изменение) того же итерабельного в вложенных циклах.

Как я уже сказал, это сложное решение, которое повредит читабельности вашего кода и затруднит его отладку. Поэтому в первую очередь следует учитывать другие решения, такие как списки, упомянутые в David Raznick . При этом я нашел моменты, когда этот класс был полезен для меня и был более простым в использовании, чем отслеживание индексов элементов, которые нужно удалить.


Изменить: как упоминалось в комментариях, этот ответ на самом деле не представляет проблемы, для которой этот подход обеспечивает решение. Я попытаюсь обратиться к этому здесь:

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

то есть.

newList = [i for i in oldList if testFunc(i)]

Но что, если результат testFunc уже зависит от элементов, которые были добавлены в newList? Или элементы, все еще находящиеся в oldList, которые могут быть добавлены далее? Возможно, все еще есть способ использовать понимание списка, но он начнет терять его изящество, и для меня легче изменить список на месте.

Ниже приведен один из примеров алгоритма, который страдает от указанной проблемы. Алгоритм уменьшит список, так что ни один элемент не будет кратен никакому другому элементу.

randInts = [70, 20, 61, 80, 54, 18, 7, 18, 55, 9]
fRandInts = FluidIterable(randInts)
fRandIntsIter = fRandInts.__iter__()
# for each value in the list (outer loop)
# test against every other value in the list (inner loop)
for i in fRandIntsIter:
    print(' ')
    print('outer val: ', i)
    innerIntsIter = fRandInts.__iter__()
    for j in innerIntsIter:
        innerIndex = innerIntsIter.currentIndex
        # skip the element that the outloop is currently on
        # because we don't want to test a value against itself
        if not innerIndex == fRandIntsIter.currentIndex:
            # if the test element, j, is a multiple 
            # of the reference element, i, then remove 'j'
            if j%i == 0:
                print('remove val: ', j)
                # remove element in place, without breaking the
                # iteration of either loop
                del fRandInts[innerIndex]
            # end if multiple, then remove
        # end if not the same value as outer loop
    # end inner loop
# end outerloop

print('')
print('final list: ', randInts)

Вывод и окончательный сокращенный список показаны ниже

outer val:  70

outer val:  20
remove val:  80

outer val:  61

outer val:  54

outer val:  18
remove val:  54
remove val:  18

outer val:  7
remove val:  70

outer val:  55

outer val:  9
remove val:  18

final list:  [20, 61, 7, 55, 9]

Ответ 18

Самый эффективный метод - это понимание списка, многие люди показывают свое дело, конечно, это также хороший способ получить iterator через filter.

Filter получает функцию и последовательность. Filter применяет переданную функцию к каждому элементу поочередно, а затем решает, сохранять или отбрасывать элемент в зависимости от того, является ли возвращаемое значение функции True или False.

Существует пример (получить коэффициенты в кортеже):

list(filter(lambda x:x%2==1, (1, 2, 4, 5, 6, 9, 10, 15)))  
# result: [1, 5, 9, 15]

Внимание: вы также не можете обрабатывать итераторы. Итераторы иногда лучше, чем последовательности.

Ответ 19

Вы можете написать это

for i, item in enumerate(my_list):
    if condition:
        my_list.pop(i)

Здесь i - индекс, а item - содержимое.

Ответ 20

Другие ответы правильны, что обычно бывает плохой идеей удалить из списка, который вы выполняете. Обратное повторение позволяет избежать ошибок, но гораздо сложнее следовать коду, который делает это, поэтому обычно вам лучше использовать понимание списка или filter.

Однако есть один случай, когда безопасно удалять элементы из последовательности, которую вы выполняете: если вы удаляете только один элемент во время повтора. Это может быть обеспечено с помощью return или break. Например:

for i, item in enumerate(lst):
    if item % 4 == 0:
        foo(item)
        del lst[i]
        break

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

Ответ 21

Этого достаточно, я думаю.

  list = []
     for x in somelist:
         if(condition):
            list.append(x)

ИЛИ Использование списков

Yourlist = [val for tup in somelist if condition]

Ответ 22

Я могу придумать три подхода к решению вашей проблемы. В качестве примера я создам случайный список кортежей somelist = [(1,2,3), (4,5,6), (3,6,6), (7,8,9), (15,0,0), (10,11,12)]. Условие, которое я выбираю, является sum of elements of a tuple = 15. В конечном списке мы будем иметь только те кортежи, сумма которых не равна 15.

То, что я выбрал, является случайным образом выбранным примером. Не стесняйтесь изменять список кортежей и условие, которое я выбрал.

Метод 1.> Использовать фреймворк, который вы предложили (где один заполняет код внутри цикла for). Я использую небольшой код с del для удаления кортежа, который соответствует указанному условию. Однако этот метод пропустит кортеж (который удовлетворяет указанному условию), если два последовательно расположенных кортежа удовлетворяют заданному условию.

for tup in somelist:
    if ( sum(tup)==15 ): 
        del somelist[somelist.index(tup)]

print somelist
>>> [(1, 2, 3), (3, 6, 6), (7, 8, 9), (10, 11, 12)]

Метод 2.> Построить новый список, содержащий элементы (кортежи), где данное условие не выполняется (это то же самое, что удаление элементов списка, где выполняется данное условие). Ниже приведен код для этого:

newlist1 = [somelist[tup] for tup in range(len(somelist)) if(sum(somelist[tup])!=15)]

print newlist1
>>>[(1, 2, 3), (7, 8, 9), (10, 11, 12)]

Метод 3.> Найти индексы, в которых выполняется заданное условие, а затем использовать удаленные элементы (кортежи), соответствующие этим индексам. Ниже приведен код для этого.

indices = [i for i in range(len(somelist)) if(sum(somelist[i])==15)]
newlist2 = [tup for j, tup in enumerate(somelist) if j not in indices]

print newlist2
>>>[(1, 2, 3), (7, 8, 9), (10, 11, 12)]

Способ 1 и способ 2 быстрее, чем метод 3. Метод 2 и метод3 более эффективны, чем метод1. Я предпочитаю метод2. Для вышеупомянутого примера time(method1): time(method2): time(method3) = 1:1: 1.7

Ответ 23

цикл for будет проходить через индекс.

считай, у тебя есть список,

[5, 7, 13, 29, 65, 91]

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

ваша переменная

lis = [5, 7, 13, 29, 35, 65, 91]
       0  1   2   3   4   5   6

во время 5-й итерации,

Ваш номер 35 не был простым, поэтому вы удалили его из списка.

lis.remove(y)

а затем следующее значение (65) перейти к предыдущему индексу.

lis = [5, 7, 13, 29, 65, 91]
       0  1   2   3   4   5

так что 4-я итерация сделала указатель переместился на 5-ую..

вот почему ваш цикл не покрывает 65, так как он переместился в предыдущий индекс.

поэтому вы не должны ссылаться на список в другой переменной, которая все еще ссылается на оригинал, а не на копию.

ite = lis #dont do it will reference instead copy

поэтому сделайте копию списка, используя list[::]

теперь тебе это даст,

[5, 7, 13, 29]

Проблема в том, что вы удалили значение из списка во время итерации, после чего ваш индекс списка будет свернут.

так что вы можете попробовать понимание вместо этого.

который поддерживает все повторяемые, как, список, кортеж, dict, строка и т.д.

Ответ 24

Для всего, что имеет потенциал быть действительно большим, я использую следующее.

import numpy as np

orig_list = np.array([1, 2, 3, 4, 5, 100, 8, 13])

remove_me = [100, 1]

cleaned = np.delete(orig_list, remove_me)
print(cleaned)

Это должно быть значительно быстрее, чем что-либо еще.

Ответ 25

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

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

""" Sieve of Eratosthenes """

def generate_primes(n):
    """ Generates all primes less than n. """
    primes = list(range(2,n))
    idx = 0
    while idx < len(primes):
        p = primes[idx]
        for multiple in range(p+p, n, p):
            try:
                primes.remove(multiple)
            except ValueError:
                pass #EAFP
        idx += 1
        yield p

Ответ 26

Если вы будете использовать новый список позже, вы можете просто установить элемент в None, а затем оценить его в последующем цикле, например

for i in li:
    i = None

for elem in li:
    if elem is None:
        continue

Таким образом, вам не нужно копировать список, и это легче понять.

Ответ 27

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

Пример:

i = 0
length = len(list1)

while i < length:
    if condition:
        list1.remove(list1[i])
        i -= 1
        length -= 1

    i += 1

Ответ 28

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

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

Как отметил Дэвид, я рекомендую понимание списка, чтобы сохранить элементы, которые вы не хотите удалять.

somelist = [x for x in somelist if not determine(x)]

Ответ 29

открыть список чисел, и вы хотите удалить все нет делятся на 3,

list_number =[i for i in range(100)]

используя list comprehension, это создаст новый список и создаст новое пространство памяти

new_list =[i for i in list_number if i%3!=0]

используя функцию lambda filter, это создаст результирующий новый список и займет место памяти

new_list = list(filter(lambda x:x%3!=0, list_number))

без использования места в памяти для нового списка и изменения существующего списка

for index, value in enumerate(list_number):
    if list_number[index]%3==0:
        list_number.remove(value)