Ниже приведен код, если вы не используете jQuery. Демо
var myArray = [
{field: 'id', operator: 'eq', value: 'id'},
{field: 'cStatus', operator: 'eq', value: 'cStatus'},
{field: 'money', operator: 'eq', value: 'money'}
];
alert(myArray.length);
for(var i=0 ; i
Вы также можете использовать библиотеку подчеркивания, в которой есть много функций.
Подчеркивание - это пояс библиотека для JavaScript, которая обеспечивает большую поддержку функционального программирования
Вам нужно взять копию списка и сначала перебрать его, либо итерация завершится неудачно, что может быть неожиданным.
Например (зависит от типа списка):
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
[]
Вы можете использовать представление списка для создания нового списка, содержащего только те элементы, которые вы не хотите удалять:
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)
somelist[:] = (x for x in somelist if determine(x))
, это создаст генератор, который не может создавать лишние копии.
– Rostislav Kondratenko
29 April 2015 в 14:54
list_ass_slice()
, которая реализует somelist[:]=
вызовы PySequence_Fast()
внутренне. Эта функция всегда возвращает список, т. Е. решение @Alex Martelli, которое уже использует список вместо генератора, наиболее вероятно более эффективно
– jfs
7 May 2015 в 20:48
Другие ответы верны, что обычно удалить плохую идею из списка, который вы повторяете. Обратное повторение позволяет избежать ошибок, но гораздо сложнее следовать коду, который делает это, поэтому обычно вам лучше использовать понимание списка или filter
.
Однако есть один случай, когда безопасно удалять элементы из последовательности, которую вы выполняете: если вы удаляете только один элемент во время повтора. Это может быть обеспечено с помощью return
или break
. Например:
for i, item in enumerate(lst):
if item % 4 == 0:
foo(item)
del lst[i]
break
Это часто легче понять, чем понимание списка, когда вы выполняете некоторые операции с побочными эффектами для первого элемента в списке, который удовлетворяет некоторым условиям, а затем удаляет этот элемент из список сразу после.
Возможно, вы захотите использовать filter()
в качестве встроенного.
Подробнее проверьте здесь
Официальный учебник 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 , что делает его совершенно ясным, что вы не можете изменить список, который выполняется итерацией, за исключением самого итератора, и дает вам эффективные способы сделать это без копирования списка , Давай, Питон!
ListIterator
, но не нашел там никакого заявления, которое запрещает модификацию списка во время его повторения. (Я видел, что он запрещает remove
после add
и set
после remove
или add
, но ни один из них, похоже, не то, что вы говорите.)
– max
5 May 2017 в 11:49
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]
some_list[:] = [x for x in some_list if not some_condition(x)]
не достигается? Не отвечая на этот вопрос, почему кто-то считает, что загрузка и использование вашей 600-строчной библиотеки в комплекте с опечатками и кодом с комментариями является лучшим решением для их проблемы, чем однострочный? -1.
– Mark Amery
21 June 2016 в 22:47
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)
Этого достаточно, я думаю.
list = []
for x in somelist:
if(condition):
list.append(x)
ИЛИ Использование списков
Yourlist = [val for tup in somelist if condition]
Если вы хотите сделать что-либо еще во время итерации, может быть полезно получить как индекс (который гарантирует вам возможность ссылаться на него, например, если у вас есть список 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
так, чтобы индексы, которые вы собираетесь удалить позже, не изменяются на вас.
for i in xrange(len(somelist) - 1, -1, -1):
if some_condition(somelist, i):
del somelist[i]
Вам нужно вернуться назад, иначе это немного похоже на распиливание ветви дерева, на которой вы сидите: -)
reversed()
– ncoghlan
23 March 2011 в 08:08
enumerate
возвращает итератор, а reversed
ожидает последовательность. Думаю, вы могли бы сделать reversed(list(enumerate(somelist)))
, если не возражаете создать дополнительный список в памяти.
– drevicko
2 August 2015 в 23:27
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
Я не знаю, насколько эффективно несколько удалений сравниваются с копированием большого списка. Прокомментируйте, если у вас есть понимание.
list
как структуры данных в первую очередь должен быть тщательно рассмотрен, так как удаление из середины списка занимает линейное время в длине списка. Если вам действительно не нужен случайный доступ к k-м секвенциальному элементу, возможно, рассмотрите OrderedDict
?
– max
5 May 2017 в 11:29
newlist = []
, а затем newlist.append(array[i])
непосредственно перед del array[i]
?
– max
5 May 2017 в 11:31
list()
является связанным списком, случайный доступ дорог, если list()
является массивом, удаление является дорогостоящим, потому что им требуется переместить все последующие элементы вперед. Приличный итератор может сделать все возможное для реализации связанного списка. Однако это может быть эффективным с точки зрения пространства.
– Ciro Santilli 新疆改造中心 六四事件 法轮功
5 June 2017 в 16:08
Сразу же вы хотите создать копию списка, чтобы вы могли иметь это как ссылку, когда вы повторяете и удаляете кортежи в этом списке, которые соответствуют определенным критериям.
Тогда это зависит от какой тип списка вы хотите для вывода, будь то список удаленных кортежей или список кортежей, которые не удалены.
Как указал Дэвид, я рекомендую понимание списка, чтобы сохранить элементы, которые вы не хотите удалять.
somelist = [x for x in somelist if not determine(x)]
Возможно, было бы разумно также создать новый список, если текущий элемент списка соответствует требуемым критериям.
so:
for item in originalList:
if (item != badValue):
newList.append(item)
и избежать необходимости перекодировать весь проект с новым именем списка:
originalList[:] = newList
отметить, из Python документация:
copy.copy (x) Вернуть мелкую копию x.
copy.deepcopy (x) Вернуть глубокую копию x.
< / BLOCKQUOTE>
originalList[:] = newList[:]
глупо. Если вы не планируете использовать newList
после, вы просто ненужно скопировали его. originalList[:] = newList
будет работать нормально и сохранить дополнительный раунд копирования.
– ShadowRanger
22 October 2016 в 00:24
Вы можете попробовать для цикла в обратном порядке, поэтому для 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)
Таким образом, индекс выравнивается и не страдает от обновлений списка (независимо от того, поп-элемент или нет).
reversed(list(enumerate(some_list)))
было бы проще, чем вычислять индексы самостоятельно.
– Mark Amery
21 June 2016 в 22:49
Мне нужно было сделать что-то подобное, и в моем случае проблема была в памяти - мне нужно было объединить несколько объектов набора данных в список, после того как они сделали что-то с ними, как новый объект, и нужно было избавиться от каждой записи. сливалось воедино, чтобы не дублировать их и не взрывать память. В моем случае наличие объектов в словаре вместо списка работало нормально:
`` `
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
` ``
Ответы, предлагающие понимание списка, являются ПОЧТИ правильными - за исключением того, что они строят совершенно новый список, а затем дают ему то же имя, что и старый список, поскольку они НЕ изменяют старый список на месте. Это отличается от того, что вы делаете при выборочном удалении, как в предложении @ Леннарта - это быстрее, но если ваш список доступен через несколько ссылок, то факт, что вы просто повторно используете одну из ссылок и НЕ изменяете объект списка само по себе может привести к тонким, катастрофическим ошибкам.
К счастью, очень легко получить как скорость распознавания списков, так и необходимую семантику изменения на месте - просто код:
somelist[:] = [tup for tup in somelist if determine(tup)]
Обратите внимание на тонкую разницу с другими ответами: этот НЕ присваивает имя барда - он присваивает срезу списка, который просто является полным списком, тем самым заменяя содержимое списка в пределах того же Python, вместо того, чтобы просто повторять одну ссылку (от предыдущего объекта списка до нового объекта списка), как и другие ответы.
a
содержимым dict b
, используйте a.clear(); a.update(b)
.
– Sven Marnach
2 April 2011 в 00:51
x = ['foo','bar','baz']; y = x; x = [item for item in x if determine(item)];
Это переназначает x
на результат понимания списка, но y
все еще относится к списку original i> ['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
Для тех, кто любит функциональное программирование:
somelist[:] = filter(lambda tup: not determine(tup), somelist)
или
from itertools import ifilterfalse
somelist[:] = list(ifilterfalse(determine, somelist))
filter
и более Pythonic. 2. Если вам нужно lambda
использовать map
или filter
, список comp или genexpr всегда i> лучший вариант; map
и filter
могут быть немного быстрее, когда функция transform / predicate является встроенным Python, реализованным на C, и итерабельность не является тривиально малой, но они всегда медленнее, когда вам нужен lambda
, что listcomp / genexpr можно было бы избежать.
– ShadowRanger
22 October 2016 в 00:22
Одно возможное решение, полезно, если вы хотите не только удалить некоторые вещи, но и сделать что-то со всеми элементами в одном цикле:
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
bad
вещи, что-то сделать с ним, а также сделать что-то с good
вещами в одном цикле?
– Alexey
16 March 2018 в 08:38
alist[:]
). И поскольку вы, возможно, делаете что-то необычное, на самом деле он имеет прецедент. Хорошая ревизия хороша. Возьми мой верх.
– Beefster
29 March 2018 в 19:14
Этот ответ был первоначально написан в ответ на вопрос, который с тех пор был отмечен как дубликат: Удаление координат из списка на 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 () only принимает единственный аргумент. Итак, как мы можем заставить remove () работать с вашим списком? Нам нужно выяснить, что представляет собой каждый элемент вашего списка. В этом случае каждый из них является кортежем. Чтобы увидеть это, давайте обратимся к одному элементу списка (индексирование начинается с 0):
>>> L1[1]
(5, 6)
>>> type(L1[1])
<type 'tuple'>
Aha! Каждый элемент 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», когда ему передается список. Для практических целей вы можете думать о нем как о создании обратной копии своих аргументов. Это рекомендуемое мной решение.
remove()
должен перебирать список WHOLE для каждой итерации, поэтому это займет много времени. – vitiral 12 February 2015 в 00:22somelist[:] = (x for x in somelist if determine(x))
, это создаст генератор, который не может создавать лишние копии. – Rostislav Kondratenko 29 April 2015 в 14:54list_ass_slice()
, которая реализуетsomelist[:]=
вызовыPySequence_Fast()
внутренне. Эта функция всегда возвращает список, т. Е. решение @Alex Martelli, которое уже использует список вместо генератора, наиболее вероятно более эффективно – jfs 7 May 2015 в 20:48