Удаление нескольких элементов из списка

Можно ли удалить несколько элементов из списка одновременно? Если я хочу удалить элементы с индексами 0 и 2 и попробовать что-то вроде del somelist[0], а затем del somelist[2], второе утверждение фактически удалит somelist[3].

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

Ответ 1

Вероятно, это не лучшее решение для этой проблемы:

indices = 0, 2
somelist = [i for j, i in enumerate(somelist) if j not in indices]

Ответ 2

Мне почему-то не нравится какой-либо из ответов. Да, они работают, но, строго говоря, большинство из них не удаляют элементы в списке, не так ли? (Но сделав копию, а затем заменив исходную на отредактированную копию).

Почему бы не просто сначала удалить более высокий индекс?

Есть ли причина для этого? Я бы просто сделал:

for i in sorted(indices, reverse=True):
    del somelist[i]

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

Мне что-то не хватает, по какой-либо причине НЕ удалять в обратном порядке?

Ответ 3

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

Если ваши объекты смежны, вы можете использовать синтаксис назначения фрагментов:

a[2:10] = []

Ответ 4

Как функция:

def multi_delete(list_, *args):
    indexes = sorted(list(args), reverse=True)
    for index in indexes:
        del list_[index]
    return list_

Запускается в n log (n) времени, что должно сделать его самым быстрым правильным решением.

Ответ 5

Как специализация ответа Грега, вы можете даже использовать расширенный синтаксис среза. например. Если вы хотите удалить пункты 0 и 2:

>>> a= [0, 1, 2, 3, 4]
>>> del a[0:3:2]
>>> a
[1, 3, 4]

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

Ответ 6

Вы можете использовать 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.

Ответ 7

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

Наша цель - удалить все гласные, которые предварительно вычисляются как индексы 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.

Ответ 8

Я являюсь новичком в 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 имеет известный формат, например, всегда числовое...

Ответ 9

Вот альтернатива, которая не использует 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].

Ответ 10

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

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

Ответ 11

Альтернативный метод определения списка, который использует значения индекса списка:

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

Ответ 12

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

В O(n) решение будет:

indices = {0, 2}
somelist = [i for j, i in enumerate(somelist) if j not in indices]

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

Ответ 13

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() не является хорошей идеей, поскольку оно не может обрабатывать дублированные элементы в списке.

Ответ 14

Удаление метода приведет к большому смещению элементов списка. Я думаю, лучше сделать копию:

...
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
...

Ответ 15

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

del (foo['bar'],foo['baz'])

будет recusrively удалять foo['bar'], тогда foo['baz']

Ответ 16

мы можем сделать это с помощью цикла 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

Ответ 17

Для индексов 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)

Ответ 18

Я хотел бы сравнить различные решения, которые упростили поворот регуляторов.

Сначала я создал свои данные:

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.

Ответ 19

Вы можете использовать эту логику:

my_list = ['word','yes','no','nice']

c=[b for i,b in enumerate(my_list) if not i in (0,2,3)]

print c

Ответ 20

Вы можете сделать это на дикторе, а не в списке. В элементе списка последовательно. В 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())] 

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

Ответ 21

На самом деле я могу думать о двух способах этого:

  • нарисуйте список как (это удаляет 1-й, 3-й и 8-й элементы)

    somelist = somelist [1: 2] + somelist [3: 7] + somelist [8:]

  • делать это на месте, но по одному за раз:

    somelist.pop(2) somelist.pop(0)

Ответ 22

Обобщение комментария из @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]

Ответ 23

Импортирование только по этой причине может быть чрезмерным, но если вы все равно используете 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']

Ответ 24

some_list.remove(some_list[max(i, j)])

Позволяет избежать затрат на сортировку и необходимость явного копирования списка.

Ответ 25

Еще одна реализация идеи удаления из высшего индекса.

for i in range(len(yourlist)-1, -1, -1):
    del yourlist(i)

Ответ 26

Как насчет одного из них (я очень плохо знаком с 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)

["Атлантика", "Тихий океан", "Индийский"]