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

107

В python я знаю, как удалять элементы из списка.

item_list = ['item', 5, 'foo', 3.14, True]
item_list.remove('item')
item_list.remove(5)

Этот код выше удаляет значения 5 и item из item_list. Но когда нужно удалить много вещей, мне приходится писать много строк

item_list.remove("something_to_remove")

Если я знаю индекс того, что удаляю, я использую:

del item_list[x]

где x - индекс элемента, который я хочу удалить.

Если я знаю индекс всех чисел, которые хочу удалить, я использую какой-то цикл для delэлементов в индексах.

Но что, если я не знаю индексы элементов, которые хочу удалить?

Я попробовал item_list.remove('item', 'foo'), но получил сообщение об ошибке, требующее removeтолько одного аргумента.

Есть ли способ удалить несколько элементов из списка одним оператором?

PS Я использовал delи remove. Может кто-нибудь объяснить разницу между этими двумя, или они одинаковы?

Спасибо

RandomCoder
источник
1
Чтобы ответить на ваш второй вопрос: delудаляет элемент по его индексу. removeФункция списка находит индексировать элемент , а затем вызывает delпо этому показателю.
Аарон Кристиансен
Возможный дубликат
удаления

Ответы:

161

В Python создать новый объект часто лучше, чем изменять существующий:

item_list = ['item', 5, 'foo', 3.14, True]
item_list = [e for e in item_list if e not in ('item', 5)]

Что эквивалентно:

item_list = ['item', 5, 'foo', 3.14, True]
new_list = []
for e in item_list:
    if e not in ('item', 5):
        new_list.append(e)
item_list = new_list

В случае большого списка отфильтрованных значений (здесь ('item', 5)небольшой набор элементов) использование a setможет привести к повышению производительности, поскольку inоперация выполняется в O (1):

item_list = [e for e in item_list if e not in {'item', 5}]

Обратите внимание, что, как объясняется в комментариях и предлагается здесь , следующее может сэкономить еще больше времени, избегая создания набора в каждом цикле:

unwanted = {'item', 5}
item_list = [e for e in item_list if e not in unwanted]

Цветения фильтр также является хорошим решением , если память не дешево.

Aluriak
источник
Мне нравится первый ответ. Я не буду составлять новый список, и это хорошо. Спасибо!
RandomCoder
Оптимизирован ли набор для Python 2 или оптимизирован только для Python 3? Под этим я подразумеваю, создается ли набор только один раз при генерации байт-кода?
Har
Набор по определению оптимизирован для inработы. См. Этот тест для сравнения четырех примитивных структур данных. Да, набор создается в каждом цикле, как предлагается здесь , следовательно, сохранение набора в специальной переменной для использования в выражении генератора может сэкономить время.
aluriak
@RandomCoder Фактически вы создаете новый список, вы просто повторно используете имя. Вы можете проверить это, сравнив id(item_list)до и после item_list = [e for e in item_list if e not in ('item', 5)]. Проверьте мой ответ, чтобы узнать, как изменить список на месте.
Darkonaut 02
20
item_list = ['item', 5, 'foo', 3.14, True]
list_to_remove=['item', 5, 'foo']

окончательный список после удаления должен быть следующим

final_list=[3.14, True]

Однострочный код

final_list= list(set(item_list).difference(set(list_to_remove)))

вывод будет следующим

final_list=[3.14, True]
Аакаш Гоэль
источник
13
нет, он перемешивает элементы в списке. Используйте только в том случае, если порядок элементов не имеет значения, что случается довольно часто.
поглотитель
5
Это также удалит дубликаты из списка. Хотя это не имеет значения для списка примеров
tschale
1
Этот ответ неверен и может вызвать серьезные ошибки. Почему за него проголосовали?
omerfarukdogan
1
Удалит дубликаты! Ответ может вызвать серьезные ошибки, пожалуйста, не используйте.
user2698178
2

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

>>> item_list = ['item', 5, 'foo', 3.14, True]
>>> item_list = set(item_list) - {'item', 5}
>>> item_list
{True, 3.14, 'foo'}
>>> # you can cast it again in a list-from like so
>>> item_list = list(item_list)
>>> item_list
[True, 3.14, 'foo']
Анварвич
источник
6
Однако не поддерживает порядок объектов.
Astrid
А также удалит дубликаты, которые потенциально существуют в списке.
kyriakosSt,
1

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


def removed(items, original_list, only_duplicates=False, inplace=False):
    """By default removes given items from original_list and returns
    a new list. Optionally only removes duplicates of `items` or modifies
    given list in place.
    """
    if not hasattr(items, '__iter__') or isinstance(items, str):
        items = [items]

    if only_duplicates:
        result = []
        for item in original_list:
            if item not in items or item not in result:
                result.append(item)
    else:
        result = [item for item in original_list if item not in items]

    if inplace:
        original_list[:] = result
    else:
        return result

Расширение строки документации:

"""
Examples:
---------

    >>>li1 = [1, 2, 3, 4, 4, 5, 5]
    >>>removed(4, li1)
       [1, 2, 3, 5, 5]
    >>>removed((4,5), li1)
       [1, 2, 3]
    >>>removed((4,5), li1, only_duplicates=True)
       [1, 2, 3, 4, 5]

    # remove all duplicates by passing original_list also to `items`.:
    >>>removed(li1, li1, only_duplicates=True)
      [1, 2, 3, 4, 5]

    # inplace:
    >>>removed((4,5), li1, only_duplicates=True, inplace=True)
    >>>li1
        [1, 2, 3, 4, 5]

    >>>li2 =['abc', 'def', 'def', 'ghi', 'ghi']
    >>>removed(('def', 'ghi'), li2, only_duplicates=True, inplace=True)
    >>>li2
        ['abc', 'def', 'ghi']
"""

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

li1 = [1, 2, 3, 4, 4, 5, 5]
li2 = li1
# then rebind li1 to the new list without the value 4
li1 = removed(4, li1)
# you end up with two separate lists where li2 is still pointing to the 
# original
li2
# [1, 2, 3, 4, 4, 5, 5]
li1
# [1, 2, 3, 5, 5]

Это может быть или не быть тем поведением, которое вы хотите.

Darkonaut
источник
1

Вы можете использовать filterfalse функцию из itertools модуля

пример

import random
from itertools import filterfalse

random.seed(42)

data = [random.randrange(5) for _ in range(10)]
clean = [*filterfalse(lambda i: i == 0, data)]
print(f"Remove 0s\n{data=}\n{clean=}\n")


clean = [*filterfalse(lambda i: i in (0, 1), data)]
print(f"Remove 0s and 1s\n{data=}\n{clean=}")

Вывод:

Remove 0s
data=[0, 0, 2, 1, 1, 1, 0, 4, 0, 4]
clean=[2, 1, 1, 1, 4, 4]

Remove 0s and 1s
data=[0, 0, 2, 1, 1, 1, 0, 4, 0, 4]
clean=[2, 4, 4]
Влад Безден
источник
0

Но что, если я не знаю индексы элементов, которые хочу удалить?

Я не совсем понимаю, почему вам не нравится .remove, но чтобы получить первый индекс, соответствующий значению, используйте .index (value):

ind=item_list.index('item')

затем удалите соответствующее значение:

del item_list.pop[ind]

.index (значение) получает первое вхождение значения, а .remove (значение) удаляет первое вхождение значения

aless80
источник
Рассмотрите возможность использования del item_list[ind]вместо, popесли вам не нужно значение результата.
Кодзиро
-1

Вы можете использовать это -

Предположим, у нас есть список, l = [1,2,3,4,5]

Мы хотим удалить последние два элемента в одном выражении

del l[3:]

У нас есть вывод:

l = [1,2,3]

Будь проще

Кришна Сингхал
источник