Ответ 1
Вероятно, это не лучшее решение для этой проблемы:
indices = 0, 2
somelist = [i for j, i in enumerate(somelist) if j not in indices]
Можно ли удалить несколько элементов из списка одновременно? Если я хочу удалить элементы с индексами 0 и 2 и попробовать что-то вроде del somelist[0]
, а затем del somelist[2]
, второе утверждение фактически удалит somelist[3]
.
Я полагаю, что всегда могу сначала удалить элементы с более высоким номером, но я надеюсь, что есть лучший способ.
Вероятно, это не лучшее решение для этой проблемы:
indices = 0, 2
somelist = [i for j, i in enumerate(somelist) if j not in indices]
Мне почему-то не нравится какой-либо из ответов. Да, они работают, но, строго говоря, большинство из них не удаляют элементы в списке, не так ли? (Но сделав копию, а затем заменив исходную на отредактированную копию).
Почему бы не просто сначала удалить более высокий индекс?
Есть ли причина для этого? Я бы просто сделал:
for i in sorted(indices, reverse=True):
del somelist[i]
Если вы действительно не хотите удалять элементы в обратном направлении, то я думаю, вы должны просто отменить значения индексов, которые больше, чем последний удаленный индекс (не может действительно использовать тот же индекс, поскольку у вас есть другой список ) или используйте копию списка (который не будет "удалять", а заменяет оригинал отредактированной копией).
Мне что-то не хватает, по какой-либо причине НЕ удалять в обратном порядке?
Если вы удаляете несколько несмежных элементов, то то, что вы описываете, является лучшим способом (и да, обязательно начинайте с самого высокого индекса).
Если ваши объекты смежны, вы можете использовать синтаксис назначения фрагментов:
a[2:10] = []
Как функция:
def multi_delete(list_, *args):
indexes = sorted(list(args), reverse=True)
for index in indexes:
del list_[index]
return list_
Запускается в n log (n) времени, что должно сделать его самым быстрым правильным решением.
Как специализация ответа Грега, вы можете даже использовать расширенный синтаксис среза. например. Если вы хотите удалить пункты 0 и 2:
>>> a= [0, 1, 2, 3, 4]
>>> del a[0:3:2]
>>> a
[1, 3, 4]
Это не распространяется на любой произвольный выбор, конечно, но он, безусловно, может работать для удаления любых двух элементов.
Вы можете использовать numpy.delete
следующим образом:
import numpy as np
a = ['a', 'l', 3.14, 42, 'u']
I = [0, 2]
np.delete(a, I).tolist()
# Returns: ['l', '42', 'u']
Если вы не возражаете, в конце концов с массивом numpy
в конце, вы можете оставить .tolist()
. Вы также должны увидеть некоторые важные улучшения скорости, сделав это более масштабируемым решением. Я не тестировал его, но numpy
операции скомпилировали код, написанный либо в C, либо в Fortran.
Итак, вы действительно хотите удалить несколько элементов за один проход? В этом случае позиция следующего элемента для удаления будет смещена, однако многие из них были удалены ранее.
Наша цель - удалить все гласные, которые предварительно вычисляются как индексы 1, 4 и 7. Обратите внимание, что его важные индексы to_delete находятся в порядке возрастания, иначе это не сработает.
to_delete = [1, 4, 7]
target = list("hello world")
for offset, index in enumerate(to_delete):
index -= offset
del target[index]
Было бы сложнее, если бы вы хотели удалить элементы в любом порядке. IMO, сортировка to_delete
может быть проще, чем выяснять, когда вы должны или не должны вычитать из index
.
Я являюсь новичком в Python, и мое программирование на данный момент является грубым и грязным, если не сказать больше, но мое решение состояло в том, чтобы использовать комбинацию основных команд, которые я узнал в ранних учебниках:
SomeList = [1,2,3,4,5,6,7,8,10]
Rem = [0,5,7]
for i in Rem:
SomeList[i]='!' # mark for deletion
for i in range(0,SomeList.count('!')):
SomeList.remove('!') # remove
print SomeList
Очевидно, что из-за необходимости выбора символа "знак для удаления" это имеет свои ограничения.
Что касается производительности как размера шкалы списков, я уверен, что мое решение не оптимально. Тем не менее, это просто, что, я надеюсь, обращается к другим новичкам и будет работать в простых случаях, когда SomeList имеет известный формат, например, всегда числовое...
Вот альтернатива, которая не использует enumerate() для создания кортежей (как в исходном ответе SilentGhost).
Это кажется мне более читаемым. (Может быть, я буду чувствовать себя иначе, если бы у меня была привычка использовать перечисление.) CAVEAT: Я не тестировал производительность двух подходов.
# Returns a new list. "lst" is not modified.
def delete_by_indices(lst, indices):
indices_as_set = set(indices)
return [ lst[i] for i in xrange(len(lst)) if i not in indices_as_set ]
ПРИМЕЧАНИЕ: синтаксис Python 2.7. Для Python 3, xrange
= > range
.
Использование:
lst = [ 11*x for x in xrange(10) ]
somelist = delete_by_indices( lst, [0, 4, 5])
somelist:
[11, 22, 33, 66, 77, 88, 99]
--- БОНУС ---
Удалить несколько значений из списка. То есть у нас есть значения, которые мы хотим удалить:
# Returns a new list. "lst" is not modified.
def delete__by_values(lst, values):
values_as_set = set(values)
return [ x for x in lst if x not in values_as_set ]
Использование:
somelist = delete__by_values( lst, [0, 44, 55] )
somelist:
[11, 22, 33, 66, 77, 88, 99]
Это тот же ответ, что и раньше, но на этот раз мы предоставили VALUES для удаления [0, 44, 55]
.
вот еще один метод, который удаляет элементы на месте. также, если ваш список действительно длинный, он быстрее.
>>> a = range(10)
>>> remove = [0,4,5]
>>> from collections import deque
>>> deque((list.pop(a, i) for i in sorted(remove, reverse=True)), maxlen=0)
>>> timeit.timeit('[i for j, i in enumerate(a) if j not in remove]', setup='import random;remove=[random.randrange(100000) for i in range(100)]; a = range(100000)', number=1)
0.1704120635986328
>>> timeit.timeit('deque((list.pop(a, i) for i in sorted(remove, reverse=True)), maxlen=0)', setup='from collections import deque;import random;remove=[random.randrange(100000) for i in range(100)]; a = range(100000)', number=1)
0.004853963851928711
Альтернативный метод определения списка, который использует значения индекса списка:
stuff = ['a', 'b', 'c', 'd', 'e', 'f', 'woof']
index = [0, 3, 6]
new = [i for i in stuff if stuff.index(i) not in index]
Это возвращает:
['b', 'c', 'e', 'f']
Это было упомянуто, но каким-то образом никто не смог на самом деле правильно понять.
В O(n)
решение будет:
indices = {0, 2}
somelist = [i for j, i in enumerate(somelist) if j not in indices]
Это действительно близко к SilentGhost версии, но добавляет две фигурные скобки.
l = ['a','b','a','c','a','d']
to_remove = [1, 3]
[l[i] for i in range(0, len(l)) if i not in to_remove])
Это в основном то же самое, что и верхний проголосовавший ответ, просто другой способ его написания. Обратите внимание, что использование l.index() не является хорошей идеей, поскольку оно не может обрабатывать дублированные элементы в списке.
Удаление метода приведет к большому смещению элементов списка. Я думаю, лучше сделать копию:
...
new_list = []
for el in obj.my_list:
if condition_is_true(el):
new_list.append(el)
del obj.my_list
obj.my_list = new_list
...
технически, ответ НЕТ, что невозможно удалить два объекта в одно и то же время. Тем не менее, можно удалить два объекта в одной строке красивого питона.
del (foo['bar'],foo['baz'])
будет recusrively удалять foo['bar']
, тогда foo['baz']
мы можем сделать это с помощью цикла for, итерации по индексам после сортировки списка индексов в порядке убывания
mylist=[66.25, 333, 1, 4, 6, 7, 8, 56, 8769, 65]
indexes = 4,6
indexes = sorted(indexes, reverse=True)
for i in index:
mylist.pop(i)
print mylist
Для индексов 0 и 2 из списка А:
for x in (2,0): listA.pop(x)
Для некоторых случайных индексов для удаления из списка A:
indices=(5,3,2,7,0)
for x in sorted(indices)[::-1]: listA.pop(x)
Я хотел бы сравнить различные решения, которые упростили поворот регуляторов.
Сначала я создал свои данные:
import random
N = 16 * 1024
x = range(N)
random.shuffle(x)
y = random.sample(range(N), N / 10)
Затем я определил свои функции:
def list_set(value_list, index_list):
index_list = set(index_list)
result = [value for index, value in enumerate(value_list) if index not in index_list]
return result
def list_del(value_list, index_list):
for index in sorted(index_list, reverse=True):
del(value_list[index])
def list_pop(value_list, index_list):
for index in sorted(index_list, reverse=True):
value_list.pop(index)
Затем я использовал timeit
для сравнения решений:
import timeit
from collections import OrderedDict
M = 1000
setup = 'from __main__ import x, y, list_set, list_del, list_pop'
statement_dict = OrderedDict([
('overhead', 'a = x[:]'),
('set', 'a = x[:]; list_set(a, y)'),
('del', 'a = x[:]; list_del(a, y)'),
('pop', 'a = x[:]; list_pop(a, y)'),
])
overhead = None
result_dict = OrderedDict()
for name, statement in statement_dict.iteritems():
result = timeit.timeit(statement, number=M, setup=setup)
if overhead is None:
overhead = result
else:
result = result - overhead
result_dict[name] = result
for name, result in result_dict.iteritems():
print "%s = %7.3f" % (name, result)
Выход
set = 1.711
del = 3.450
pop = 3.618
Таким образом, победителем стал генератор с индексами в set
. И del
немного быстрее, чем pop
.
Вы можете использовать эту логику:
my_list = ['word','yes','no','nice']
c=[b for i,b in enumerate(my_list) if not i in (0,2,3)]
print c
Вы можете сделать это на дикторе, а не в списке. В элементе списка последовательно. В dict они зависят только от индекса.
Простой код, чтобы объяснить это, сделав:
>>> lst = ['a','b','c']
>>> dct = {0: 'a', 1: 'b', 2:'c'}
>>> lst[0]
'a'
>>> dct[0]
'a'
>>> del lst[0]
>>> del dct[0]
>>> lst[0]
'b'
>>> dct[0]
Traceback (most recent call last):
File "<pyshell#19>", line 1, in <module>
dct[0]
KeyError: 0
>>> dct[1]
'b'
>>> lst[1]
'c'
Способ "преобразования" списка в dict:
>>> dct = {}
>>> for i in xrange(0,len(lst)): dct[i] = lst[i]
Обратный:
lst = [dct[i] for i in sorted(dct.keys())]
В любом случае, я думаю, что лучше начать удаление из более высокого индекса, как вы сказали.
На самом деле я могу думать о двух способах этого:
нарисуйте список как (это удаляет 1-й, 3-й и 8-й элементы)
somelist = somelist [1: 2] + somelist [3: 7] + somelist [8:]
делать это на месте, но по одному за раз:
somelist.pop(2) somelist.pop(0)
Обобщение комментария из @sth. Удаление элемента в любом классе, реализующее abc.MutableSequence, а в list
в частности, выполняется с помощью магического метода __delitem__
. Этот метод работает аналогично __getitem__
, что означает, что он может принимать либо целое число, либо фрагмент. Вот пример:
class MyList(list):
def __delitem__(self, item):
if isinstance(item, slice):
for i in range(*item.indices(len(self))):
self[i] = 'null'
else:
self[item] = 'null'
l = MyList(range(10))
print(l)
del l[5:8]
print(l)
Это приведет к выводу
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 'null', 'null', 'null', 8, 9]
Импортирование только по этой причине может быть чрезмерным, но если вы все равно используете pandas
, тогда решение прост и прост:
import pandas as pd
stuff = pd.Series(['a','b','a','c','a','d'])
less_stuff = stuff[stuff != 'a'] # define any condition here
# results ['b','c','d']
some_list.remove(some_list[max(i, j)])
Позволяет избежать затрат на сортировку и необходимость явного копирования списка.
Еще одна реализация идеи удаления из высшего индекса.
for i in range(len(yourlist)-1, -1, -1):
del yourlist(i)
Как насчет одного из них (я очень плохо знаком с Python, но они кажутся нормальными):
ocean_basin = ['a', 'Atlantic', 'Pacific', 'Indian', 'a', 'a', 'a']
for i in range(1, (ocean_basin.count('a') + 1)):
ocean_basin.remove('a')
print(ocean_basin)
["Атлантика", "Тихий океан", "индиец"]
ob = ['a', 'b', 4, 5,'Atlantic', 'Pacific', 'Indian', 'a', 'a', 4, 'a']
remove = ('a', 'b', 4, 5)
ob = [i for i in ob if i not in (remove)]
print(ob)
["Атлантика", "Тихий океан", "Индийский"]