Usuń wiele elementów z listy Pythona w jednej instrukcji


107

W Pythonie wiem, jak usuwać elementy z listy.

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

Powyższy kod usuwa wartości 5 i „item” z item_list. Ale kiedy jest dużo rzeczy do usunięcia, muszę napisać wiele linijek

item_list.remove("something_to_remove")

Jeśli znam indeks tego, co usuwam, używam:

del item_list[x]

gdzie x jest indeksem elementu, który chcę usunąć.

Jeśli znam indeks wszystkich liczb, które chcę usunąć, użyję jakiejś pętli do delelementów w indeksach.

Ale co, jeśli nie znam wskaźników pozycji, które chcę usunąć?

Próbowałem item_list.remove('item', 'foo'), ale pojawił się błąd, który mówi, że removewymaga tylko jednego argumentu.

Czy istnieje sposób na usunięcie wielu pozycji z listy w jednym wyciągu?

PS Użyłem deli remove. Czy ktoś może wyjaśnić różnicę między tymi dwoma, czy są one takie same?

Dzięki


1
Odpowiadając na drugie pytanie: delusuwa element według jego indeksu. removeFunkcją liście znajdzie indeks elementu, a następnie wywołuje delw tym indeksie.
Aaron Christiansen

Możliwy duplikat
usuwania

Odpowiedzi:


160

W Pythonie często lepiej jest utworzyć nowy obiekt niż zmodyfikować istniejący:

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

Co jest równoważne z:

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

W przypadku dużej listy odfiltrowanych wartości (tutaj ('item', 5)jest mały zestaw elementów), użycie setmoże prowadzić do poprawy wydajności, ponieważ inoperacja jest w O (1):

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

Zauważ, że jak wyjaśniono w komentarzach i zasugerowano tutaj , poniższe mogą zaoszczędzić jeszcze więcej czasu, unikając tworzenia zestawu w każdej pętli:

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

ZA Filtr kwitną jest również dobrym rozwiązaniem, jeśli pamięć nie jest tanie.


Podoba mi się pierwsza odpowiedź. Nie tworzę nowej listy, co jest dobre. Dzięki!
RandomCoder

Czy zestaw jest zoptymalizowany w Pythonie 2, czy jest zoptymalizowany tylko w Pythonie 3? Rozumiem przez to, czy zestaw jest tworzony tylko raz, gdy generowany jest kod bajtowy?
Har

Zestaw jest z definicji zoptymalizowany do indziałania. Zobacz te wzorce, aby porównać cztery pierwotne struktury danych. Tak, zestaw jest budowany w każdej pętli, jak sugerowano tutaj , w konsekwencji zapisanie zestawu w dedykowanej zmiennej do użycia w wyrażeniu generatora może zaoszczędzić czas.
aluriak

@RandomCoder Tworzysz nową listę, po prostu ponownie używasz nazwy. Możesz to sprawdzić, porównując id(item_list)przed i po item_list = [e for e in item_list if e not in ('item', 5)]. Sprawdź moją odpowiedź, aby zobaczyć, jak zmodyfikować listę w miejscu.
Darkonaut

20
item_list = ['item', 5, 'foo', 3.14, True]
list_to_remove=['item', 5, 'foo']

ostateczna lista po usunięciu powinna wyglądać następująco

final_list=[3.14, True]

Kod jednowierszowy

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

wynik byłby następujący

final_list=[3.14, True]

13
nie, tasuje pozycje na liście. Używaj tylko wtedy, gdy kolejność przedmiotów nie ma znaczenia, co dzieje się dość często.
padlinożerca

5
Spowoduje to również usunięcie duplikatów z listy. Nie żeby miało to jednak znaczenie dla przykładowej listy
tschale

1
Ta odpowiedź jest nieprawidłowa i może powodować poważne błędy, dlaczego jest przegłosowana?
omerfarukdogan

1
Usunie duplikaty! Odpowiedź może spowodować poważne błędy, proszę nie używać.
user2698178

2

Nie wiem, dlaczego wszyscy zapomnieli wspomnieć o niesamowitych możliwościach sets w Pythonie. Możesz po prostu przesłać listę do zestawu, a następnie usunąć wszystko, co chcesz usunąć, w prostym wyrażeniu, takim jak:

>>> 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
Nie zachowuje jednak kolejności obiektów.
Astrid

A także usunie duplikaty, które potencjalnie istnieją na liście.
kyriakosSt

1

Ponownie publikuję moją odpowiedź stąd, ponieważ widziałem, że pasuje również tutaj. Pozwala usunąć wiele wartości lub usunąć tylko duplikaty tych wartości i zwraca nową listę lub modyfikuje daną listę w miejscu.


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

Rozszerzenie Docstring:

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

Powinieneś mieć jasność co do tego, co naprawdę chcesz zrobić, zmodyfikować istniejącą listę lub utworzyć nową listę z brakującymi określonymi elementami. Ważne jest, aby dokonać tego rozróżnienia, jeśli masz drugie odniesienie wskazujące na istniejącą listę. Jeśli masz na przykład ...

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]

To może być pożądane zachowanie, ale nie musi.


1

Możesz użyć funkcji filterfalse z itertools modułu

Przykład

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=}")

Wynik:

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

Ale co, jeśli nie znam wskaźników pozycji, które chcę usunąć?

Nie do końca rozumiem, dlaczego nie lubisz .remove, ale aby uzyskać pierwszy indeks odpowiadający wartości use .index (value):

ind=item_list.index('item')

następnie usuń odpowiednią wartość:

del item_list.pop[ind]

.index (wartość) pobiera pierwsze wystąpienie wartości, a .remove (wartość) usuwa pierwsze wystąpienie wartości


Rozważ użycie del item_list[ind]zamiast, popjeśli nie potrzebujesz wartości wyniku.
kojiro

-1

Możesz tego użyć -

Załóżmy, że mamy listę l = [1,2,3,4,5]

Chcemy usunąć ostatnie dwie pozycje w jednym wyciągu

del l[3:]

Mamy wyjście:

l = [1, 2, 3]

Nie komplikuj

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.