Почему это для цикла кажется сломать после утверждения if? [Дубликат]

Вы можете использовать lodash's findIndex , чтобы получить индекс конкретного элемента, а затем сплайсировать его.

myArray.splice(_.findIndex(myArray, function(item) {
    return item.value === 'money';
}), 1);

Обновить

Вы также можете использовать ES6's findIndex ()

Метод findIndex () возвращает индекс первого элемента в массиве, который удовлетворяет предоставленной функции тестирования. В противном случае возвращается -1.

myArray.splice(myArray.findIndex(myArray, function(item) {
    return item.value === 'money';
}), 1);

742
задан Ciro Santilli 新疆改造中心 六四事件 法轮功 28 February 2018 в 15:25
поделиться

22 ответа

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

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

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
[]
599
ответ дан Mark Amery 15 August 2018 в 21:16
поделиться
  • 1
    Можете ли вы сделать это быстрее, если вы знаете, что только некоторые из них будут удалены, т. Е. Удалите их и оставите на месте вместо их повторной записи? – highBandWidth 20 April 2011 в 20:25
  • 2
    Zen # 3, Simple лучше, чем сложный. Получает мой голос! – jdero 9 August 2013 в 19:55
  • 3
    почему второй работает? – Zen 18 June 2014 в 13:52
  • 4
    @Zen Потому что второй выполняет итерацию над копией списка. Поэтому, когда вы изменяете исходный список, вы не изменяете копию, которую вы перебираете. – Lennart Regebro 18 June 2014 в 14:47
  • 5
    Что, если мой список огромен и не может позволить себе сделать копию? – jpcgt 16 November 2014 в 00:43
  • 6
    Что лучше делать somelist [:] по сравнению со списком (somelist)? – Mariusz Jamro 4 February 2015 в 11:01
  • 7
    Обратите внимание на то, кто читает это, это очень медленно для списков. remove() должен перебирать список WHOLE для каждой итерации, поэтому это займет много времени. – vitiral 12 February 2015 в 00:22
  • 8
    @jpcgt Вы должны использовать somelist[:] = (x for x in somelist if determine(x)), это создаст генератор, который не может создавать лишние копии. – Rostislav Kondratenko 29 April 2015 в 14:54
  • 9
    @RostislavKondratenko: функция list_ass_slice(), которая реализует somelist[:]= вызовы PySequence_Fast() внутренне. Эта функция всегда возвращает список, т. Е. решение @Alex Martelli, которое уже использует список вместо генератора, наиболее вероятно более эффективно – jfs 7 May 2015 в 20:48
  • 10
    @CrazyGeek: Что вы имеете в виду, не работает? – Moberg 30 January 2017 в 11:58
604
ответ дан Mark Amery 5 September 2018 в 20:49
поделиться

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

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

5
ответ дан Bharat Mane 15 August 2018 в 21:16
поделиться

Официальный учебник Python 2 4.2. «for Statementments» говорит:

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

>>> 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']

, что и было предложено в: https://stackoverflow.com/a/1207427/895245

Документация Python 2 7.3. «Инструкция for» дает тот же совет:

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

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

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

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

30
ответ дан Ciro Santilli 新疆改造中心 六四事件 法轮功 15 August 2018 в 21:16
поделиться
  • 1
    Это именно то, о чем я думал ... К сожалению, что-то Java действительно лучше, чем Python. – Ryan 13 May 2016 в 12:41
  • 2
    Java rant (отредактировано stackoverflow.com/users/505088/david-heffernan ) Я чувствую, что этот конкретный API Python значительно уступает Java-аналогу ListIterator , что делает его кристально понятным, что вы не можете изменить список, повторяющийся, за исключением самого итератора, и дает вам эффективные способы сделать это без копирования списка. – Ciro Santilli 新疆改造中心 六四事件 法轮功 13 October 2016 в 11:36
  • 3
    @DavidHeffernan Я уважаю ваше мнение о том, полезна ли часть ответа или нет. Тем не менее, я не считаю целесообразным удалять содержание содержания абзаца в соответствии с пожеланиями автора, особенно когда контент ясен и связан с вопросом. Я взял на себя смелость отменить ваше редактирование. – max 5 May 2017 в 11:42
  • 4
    @ CiroSantilli709 大 抓捕 六四 事件 法轮功 Я прочитал ссылку на ListIterator, но не нашел там никакого заявления, которое запрещает модификацию списка во время его повторения. (Я видел, что он запрещает remove после add и set после remove или add, но ни один из них, похоже, не то, что вы говорите.) – max 5 May 2017 в 11:49
  • 5
    Это редактирование обсуждается в Meta Question @DavidHeffernan – Suraj Rao 5 May 2017 в 12:31

TLDR:

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

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, но он будет недоступен для изменения.

ie

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. Это стоит посмотреть, потому что они объясняют, что происходит в разных ситуациях. Например: Замена больших разделов списка с помощью среза. Или используя (и изменяя) то же самое итерабельное в вложенных циклах.

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


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

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

ie

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]
7
ответ дан Community 15 August 2018 в 21:16
поделиться
  • 1
    Трудно сказать, является ли это чрезмерно спроектированным, потому что непонятно, какую проблему он пытается решить; что удаляет элементы, используя этот подход, достичь того, что some_list[:] = [x for x in some_list if not some_condition(x)] не достигается? Не отвечая на этот вопрос, почему кто-то считает, что загрузка и использование вашей 600-строчной библиотеки в комплекте с опечатками и кодом с комментариями является лучшим решением для их проблемы, чем однострочный? -1. – Mark Amery 21 June 2016 в 22:47
  • 2
    @MarkAmery. Основной прецедент для случая, когда при попытке определить, должен ли элемент быть удален (или добавлен или перемещен), основанный не только на самом предмете, но и на состоянии другого элемента в списке или состоянии списка как все. Например, невозможно, чтобы в представлениях списков было написано что-то вроде some_list[:] = [x for x in some_list if not some_condition(y)], где y - это другой элемент списка из x. Невозможно написать some_list[:] = [x for x in some_list if not some_condition(intermediateStateOf_some_list)]. – Resonance 28 June 2016 в 13:27

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

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)
45
ответ дан Eli Courtwright 15 August 2018 в 21:16
поделиться

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

4
ответ дан fantabolous 15 August 2018 в 21:16
поделиться
  • 1
    Почему индекс становится более актуальным в случае, когда у вас есть список диктонов, чем в случае любого другого списка? Насколько мне известно, это не имеет смысла. – Mark Amery 21 June 2016 в 22:33
for i in xrange(len(somelist) - 1, -1, -1):
    if some_condition(somelist, i):
        del somelist[i]

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

77
ответ дан John Machin 15 August 2018 в 21:16
поделиться
  • 1
    В последних версиях Python вы можете сделать это еще более чисто, используя встроенный reversed() – ncoghlan 23 March 2011 в 08:08
  • 2
    reverseed () не создает новый список, он создает обратный итератор по поставленной последовательности. Например, enumerate (), вы должны обернуть его в список (), чтобы фактически получить список из него. Возможно, вы думаете о sorted (), который создает каждый раз каждый новый список (он должен, поэтому он может сортировать его). – ncoghlan 12 February 2015 в 07:44
  • 3
    @Mauris, потому что enumerate возвращает итератор, а reversed ожидает последовательность. Думаю, вы могли бы сделать reversed(list(enumerate(somelist))), если не возражаете создать дополнительный список в памяти. – drevicko 2 August 2015 в 23:27
  • 4
    Это O (N * M) для массивов, это очень медленно, если вы удалите много элементов из большого списка. Поэтому не рекомендуется. – Sam Watkins 15 September 2015 в 15:04
  • 5
    Обратите внимание, что в Python 3 xrange было переименовано в range. – Czechnology 13 October 2016 в 19:32

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

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

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

8
ответ дан Michael 15 August 2018 в 21:16
поделиться
  • 1
    В моем случае мне нужно переместить эти «нежелательные» элементы в другой список. У вас есть новые комментарии к этому решению? Я также думаю, что лучше использовать некоторые удаления вместо дублирования списка. – GVelascoh 5 May 2017 в 02:13
  • 2
    Это правильный ответ, если производительность является проблемой (хотя такая же, как @Alexey). Тем не менее, выбор list как структуры данных в первую очередь должен быть тщательно рассмотрен, так как удаление из середины списка занимает линейное время в длине списка. Если вам действительно не нужен случайный доступ к k-м секвенциальному элементу, возможно, рассмотрите OrderedDict? – max 5 May 2017 в 11:29
  • 3
    @GVelascoh, почему бы не создать newlist = [], а затем newlist.append(array[i]) непосредственно перед del array[i]? – max 5 May 2017 в 11:31
  • 4
    Обратите внимание, что это, скорее всего, время неэффективно: если list() является связанным списком, случайный доступ дорог, если list() является массивом, удаление является дорогостоящим, потому что им требуется переместить все последующие элементы вперед. Приличный итератор может сделать все возможное для реализации связанного списка. Однако это может быть эффективным с точки зрения пространства. – Ciro Santilli 新疆改造中心 六四事件 法轮功 5 June 2017 в 16:08

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

so:

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

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

originalList[:] = newList

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

copy.copy (x) Вернуть мелкую копию x.

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

< / BLOCKQUOTE>
9
ответ дан ntk4 15 August 2018 в 21:16
поделиться
  • 1
    Это не добавляет новой информации, которая не была принята в прошлом году. – Mark Amery 21 June 2016 в 22:36
  • 2
    Это просто и просто еще один способ взглянуть на проблему @MarkAmery. Он менее сконденсирован для тех людей, которым не нравится сжатый синтаксис кодирования. – ntk4 23 June 2016 в 03:08
  • 3
    originalList[:] = newList[:] глупо. Если вы не планируете использовать newList после, вы просто ненужно скопировали его. originalList[:] = newList будет работать нормально и сохранить дополнительный раунд копирования. – ShadowRanger 22 October 2016 в 00:24
  • 4
    Я никогда не умею запоминать разный синтаксис в мелкой и глубокой копии. Спасибо, что напомнили мне, что я снова перепутал @ShadowRanger :). Я уточнил свой ответ с более подробным объяснением. – ntk4 23 October 2016 в 02:31

Вы можете попробовать для цикла в обратном порядке, поэтому для 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)

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

3
ответ дан Queequeg 15 August 2018 в 21:16
поделиться
  • 1
    Зацикливание по reversed(list(enumerate(some_list))) было бы проще, чем вычислять индексы самостоятельно. – Mark Amery 21 June 2016 в 22:49
  • 2
    @MarkAmery не думает, что вы можете изменить список таким образом. – Queequeg 28 June 2016 в 18:29

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

`` `

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

` ``

2
ответ дан rafa 15 August 2018 в 21:16
поделиться

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

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

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

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

494
ответ дан Scharron 15 August 2018 в 21:16
поделиться
  • 1
    Как сделать то же нарезанное задание с помощью dict? В Python 2.6? – PaulMcG 25 March 2011 в 20:29
  • 2
    @Paul: Поскольку dicts неупорядочены, срезы не имеют смысла для dicts. Если вы хотите заменить содержимое dict a содержимым dict b, используйте a.clear(); a.update(b). – Sven Marnach 2 April 2011 в 00:51
  • 3
    Почему «переустановка» одной из ссылок заменяет то, что эта переменная ссылается на ошибку? Похоже, это будет только потенциальной проблемой в многопоточных приложениях, а не в однопоточном. – Derek Dahmer 7 August 2011 в 23:59
  • 4
    @Derek x = ['foo','bar','baz']; y = x; x = [item for item in x if determine(item)]; Это переназначает x на результат понимания списка, но y все еще относится к списку original ['foo','bar','baz']. Если вы ожидали, что x и y будут ссылаться на один и тот же список, вы можете ввести ошибки. Вы предотвращаете это, назначая фрагмент всего списка, как показывает Алекс, и я показываю здесь: x = ["foo","bar","baz"]; y = x; x[:] = [item for item in x if determine(item)];. Список изменен на месте. что все ссылки на список (как x, так и y здесь) относятся к новому списку. – Steven T. Snyder 15 November 2011 в 21:38
  • 5
    Опять Алекс на помощь. Он действительно машина. – Jakobovski 31 May 2016 в 11:08

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

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

или

from itertools import ifilterfalse
somelist[:] = list(ifilterfalse(determine, somelist))
35
ответ дан Tim Castelijns 15 August 2018 в 21:16
поделиться
  • 1
    1. Перечисление понятий и выражений генератора заимствовано из Haskell, чистого функционального языка; они точно такие же функциональные, как filter и более Pythonic. 2. Если вам нужно lambda использовать map или filter, список comp или genexpr всегда лучший вариант; map и filter могут быть немного быстрее, когда функция transform / predicate является встроенным Python, реализованным на C, и итерабельность не является тривиально малой, но они всегда медленнее, когда вам нужен lambda, что listcomp / genexpr можно было бы избежать. – ShadowRanger 22 October 2016 в 00:22

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

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

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

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

1
ответ дан Beefster 15 August 2018 в 21:16
поделиться

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

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

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

Yourlist = [val for tup in somelist if condition]
1
ответ дан eyllanesc 15 August 2018 в 21:16
поделиться

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

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

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

somelist = [x for x in somelist if not determine(x)]
0
ответ дан Nathan Tuggy 15 August 2018 в 21:16
поделиться

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

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
2
ответ дан Xenolion 15 August 2018 в 21:16
поделиться
  • 1
    Вы должны просто использовать понимание. Их гораздо легче понять. – Beefster 16 March 2018 в 00:46
  • 2
    Что делать, если я хочу удалить bad вещи, что-то сделать с ним, а также сделать что-то с good вещами в одном цикле? – Alexey 16 March 2018 в 08:38
  • 3
    На самом деле, я понял, что здесь есть какая-то уловка, когда вы делаете копию списка с открытым срезом (alist[:]). И поскольку вы, возможно, делаете что-то необычное, на самом деле он имеет прецедент. Хорошая ревизия хороша. Возьми мой верх. – Beefster 29 March 2018 в 19:14
0
ответ дан CENTURION 5 September 2018 в 20:49
поделиться
7
ответ дан Community 5 September 2018 в 20:49
поделиться
0
ответ дан CodeKid 29 October 2018 в 04:21
поделиться
0
ответ дан MJB 29 October 2018 в 04:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: