Prawie muszę napisać program, aby sprawdzić, czy lista ma jakieś duplikaty, a jeśli tak, to usuwa je i zwraca nową listę z elementami, które nie zostały zduplikowane / usunięte. To właśnie mam, ale szczerze mówiąc nie wiem, co robić.
def remove_duplicates():
t = ['a', 'b', 'c', 'd']
t2 = ['a', 'c', 'd']
for t in t2:
t.append(t.remove())
return t
python
algorithm
list
duplicates
intersection
Neemaximo
źródło
źródło
Odpowiedzi:
Powszechnym podejściem do uzyskania unikalnej kolekcji przedmiotów jest użycie
set
. Zestawy to nieuporządkowane kolekcje różnych obiektów. Aby utworzyć zestaw z dowolnej iteracji, możesz po prostu przekazać go do wbudowanejset()
funkcji. Jeśli później będziesz potrzebować prawdziwej listy, możesz podobnie przekazać zestaw dolist()
funkcji.Poniższy przykład powinien obejmować wszystko, co próbujesz zrobić:
Jak widać z przykładowego wyniku, oryginalne zamówienie nie jest utrzymywane . Jak wspomniano powyżej, same zestawy są kolekcjami nieuporządkowanymi, więc zamówienie zostaje utracone. Podczas konwersji zestawu z powrotem na listę tworzona jest dowolna kolejność.
Utrzymanie porządku
Jeśli kolejność jest dla Ciebie ważna, będziesz musiał użyć innego mechanizmu. Bardzo częstym rozwiązaniem jest poleganie na
OrderedDict
utrzymywaniu kolejności kluczy podczas wstawiania:Począwszy od Python 3.7 , wbudowany słownik gwarantuje również zachowanie kolejności wstawiania, więc możesz również użyć tego bezpośrednio, jeśli korzystasz z Python 3.7 lub nowszej wersji (lub CPython 3.6):
Zauważ, że może to wiązać się z pewnym nakładem na utworzenie słownika, a następnie utworzenie listy z niego. Jeśli tak naprawdę nie musisz zachowywać porządku, często lepiej jest użyć zestawu, zwłaszcza, że daje dużo więcej operacji do pracy. Sprawdź to pytanie, aby uzyskać więcej informacji i alternatywne sposoby zachowania porządku podczas usuwania duplikatów.
Na koniec zauważ, że zarówno rozwiązania,
set
jak iOrderedDict
/dict
wymagają, aby twoje przedmioty mogły być haszowalne . Zazwyczaj oznacza to, że muszą być niezmienne. Jeśli masz do czynienia z elementami, które nie są haszowalne (np. Obiekty z listy), będziesz musiał zastosować powolne podejście, w którym zasadniczo będziesz musiał porównać każdy element z każdym innym elementem w zagnieżdżonej pętli.źródło
W Pythonie 2.7 nowy sposób usuwania duplikatów z iterowalnych przy jednoczesnym zachowaniu ich w oryginalnej kolejności to:
W Pythonie 3.5 OrDERDict ma implementację C. Moje czasy wskazują, że jest to zarówno najszybsze, jak i najkrótsze z różnych podejść do Pythona 3.5.
W Pythonie 3.6 zwykły słownik stał się uporządkowany i zwarty. (Ta funkcja dotyczy CPython i PyPy, ale może nie występować w innych implementacjach). To daje nam nowy najszybszy sposób deduplikacji przy zachowaniu porządku:
W Pythonie 3.7 regularny słownik jest gwarantowany zarówno we wszystkich implementacjach. Zatem najkrótszym i najszybszym rozwiązaniem jest:
źródło
TypeError: unhashable type: 'dictlist'
Jest to jedna linijka:
list(set(source_list))
załatwi sprawę.Jest
set
to coś, co nie może mieć duplikatów.Aktualizacja: podejście zachowujące porządek składa się z dwóch linii:
W tym przypadku wykorzystujemy fakt, że
OrderedDict
zapamiętuje kolejność wstawiania kluczy i nie zmienia go, gdy wartość określonego klucza jest aktualizowana. WstawiamyTrue
jako wartości, ale możemy wstawić wszystko, wartości po prostu nie są używane. (set
działa podobnie jakdict
z ignorowanymi wartościami).źródło
source_list
jest możliwe do skrótu.źródło
frozenset
działa z zawartością, której nie można mieszać Podczas używania nadal pojawia się błąd, którego nie da się ukryćfrozenset
.Jeśli nie zależy ci na zamówieniu, po prostu zrób to:
set
Gwarantuje nie ma duplikatów.źródło
l
jest możliwe do skrótu.Aby utworzyć nową listę zachowującą kolejność pierwszych elementów duplikatów w
L
newlist=[ii for n,ii in enumerate(L) if ii not in L[:n]]
na przykład
if L=[1, 2, 2, 3, 4, 2, 4, 3, 5]
wtedynewlist
będzie[1,2,3,4,5]
To sprawdza, czy każdy nowy element nie pojawiał się wcześniej na liście przed dodaniem go. Nie potrzebuje też importu.
źródło
set
iOrderedDict
mogą mieć mniejszą zamortyzowaną złożoność czasu.Kolega wysłał mi dzisiaj zaakceptowaną odpowiedź w ramach swojego kodu w celu zapoznania się z kodem. Choć z pewnością podziwiam elegancję odpowiedzi, o której mowa, nie jestem zadowolony z tego przedstawienia. Wypróbowałem to rozwiązanie (używam zestawu, aby skrócić czas wyszukiwania)
Aby porównać wydajność, wykorzystałem losową próbkę 100 liczb całkowitych - 62 były wyjątkowe
Oto wyniki pomiarów
Co się stanie, jeśli zestaw zostanie usunięty z rozwiązania?
Rezultat nie jest tak zły, jak w przypadku zamówienia OrDERDict , ale wciąż więcej niż 3 razy w porównaniu z oryginalnym rozwiązaniem
źródło
def unique(iterable):
:;seen = set()
;seen_add = seen.add
;return [item for item in iterable if not item in seen and not seen_add(item)]
Istnieją również rozwiązania wykorzystujące Pandy i Numpy. Oba zwracają tablicę numpy, więc musisz użyć funkcji,
.tolist()
jeśli chcesz mieć listę.Rozwiązanie Pandy
Korzystanie z funkcji Pandy
unique()
:Rozwiązanie Numpy
Korzystanie z funkcji numpy
unique()
.Zauważ, że numpy.unique () również sortuje wartości . Lista
t2
jest więc sortowana. Jeśli chcesz zachować porządek, skorzystaj z następującej odpowiedzi :Rozwiązanie nie jest tak eleganckie w porównaniu z innymi, jednak w porównaniu z pandas.unique (), numpy.unique () pozwala również sprawdzić, czy zagnieżdżone tablice są unikalne wzdłuż jednej wybranej osi.
źródło
Kolejny sposób:
źródło
keys()
zwraca obiekt widoku słownika, a nie listę.Proste i łatwe:
Wynik:
źródło
in
jest operacją O (n) icleanlist
będziesz mieć co najwyżejn
liczby => najgorszy przypadek ~ O (n ^ 2)W tej odpowiedzi będą dwie sekcje: Dwa unikalne rozwiązania i wykres prędkości dla konkretnych rozwiązań.
Usuwanie zduplikowanych elementów
Większość z tych odpowiedzi usuwa tylko zduplikowane elementy, które można haszować , ale to pytanie nie oznacza, że nie tylko potrzebują haszowanych przedmiotów, co oznacza, że zaoferuję niektóre rozwiązania, które nie wymagają haszowania .
collections.Counter to potężne narzędzie w standardowej bibliotece, które może być do tego idealne. Jest tylko jedno inne rozwiązanie, które zawiera nawet Licznik. Jednak to rozwiązanie ogranicza się również do kluczy mieszalnych .
Aby zezwolić na klucze nieukrywalne w Counter, stworzyłem klasę Container, która spróbuje uzyskać domyślną funkcję skrótu obiektu, ale jeśli zawiedzie, spróbuje użyć funkcji tożsamości. Definiuje także metodę eq i metodę skrótu . To powinno wystarczyć, aby pozwolić naszym produktom na niewymagalne elementy. Obiekty, których nie można skasować, będą traktowane tak, jakby można je było haszować. Jednak ta funkcja skrótu używa tożsamości dla obiektów nieukończonych, co oznacza, że dwa równe obiekty, których oba są nieukończalne, nie będą działać. Sugeruję zastąpienie tego i zmianę go w celu użycia skrótu równoważnego typu zmiennego (np. Użycie
hash(tuple(my_list))
ifmy_list
jest listą).Stworzyłem również dwa rozwiązania. Kolejne rozwiązanie, które utrzymuje kolejność elementów, wykorzystując podklasę OrDERDict i Counter o nazwie „OrdersCounter”. Teraz oto funkcje:
remd to sortowanie bez uporządkowania, oremd to sortowanie uporządkowane. Możesz wyraźnie powiedzieć, który jest szybszy, ale i tak wyjaśnię. Nieuporządkowane sortowanie jest nieco szybsze. Przechowuje mniej danych, ponieważ nie potrzebuje porządku.
Teraz chciałem też pokazać porównanie prędkości dla każdej odpowiedzi. Zrobię to teraz.
Która funkcja jest najszybsza?
Do usuwania duplikatów zebrałem 10 funkcji z kilku odpowiedzi. Obliczyłem prędkość każdej funkcji i umieściłem ją na wykresie za pomocą matplotlib.pyplot .
Podzieliłem to na trzy rundy wykresów. Hashable to dowolny obiekt, który może być haszowany, hashable to każdy obiekt, który nie może być haszowany. Sekwencja uporządkowana to sekwencja, która zachowuje porządek, sekwencja nieuporządkowana nie zachowuje porządku. Oto kilka innych terminów:
Unordered Hashable był dla każdej metody, która usuwa duplikaty, co niekoniecznie musi zachowywać porządek. Nie musiało to działać na rzeczy nieskrępowane, ale mogło.
Uporządkowany Hashable był dla każdej metody, która zachowywała kolejność pozycji na liście, ale nie musiał działać dla nieusuwalnych, ale mógł.
Order Unhashable to dowolna metoda, która zachowuje porządek pozycji na liście i działa na niehashable.
Na osi y jest czas w sekundach.
Na osi X znajduje się liczba, do której zastosowano funkcję.
Wygenerowaliśmy sekwencje dla nieuporządkowanych skrótów i uporządkowanych skrótów z następującym zrozumieniem:
[list(range(x)) + list(range(x)) for x in range(0, 1000, 10)]
W przypadku zamówionych elementów nieukończonych:
[[list(range(y)) + list(range(y)) for y in range(x)] for x in range(0, 1000, 10)]
Zauważ, że w zakresie jest „krok”, ponieważ bez niego zajęłoby to 10 razy więcej. Również dlatego, że moim osobistym zdaniem myślałem, że może to wyglądać trochę łatwiej.
Zwróć też uwagę, że klawisze legendy są tym, co starałem się odgadnąć jako najbardziej istotne części funkcji. Co do funkcji, która jest najgorsza lub najlepsza? Wykres mówi sam za siebie.
Po ustaleniu, oto wykresy.
Nieuporządkowane haszysze
(Zbliżony)
Zamówione haszysze
(Zbliżony)
Zamówione Unhashables
(Zbliżony)
źródło
Miałem na liście dykt, więc nie mogłem zastosować powyższego podejścia. Dostałem błąd:
Więc jeśli zależy Ci na zamówieniu i / lub niektóre przedmioty są nie do zniesienia . Może się to przydać:
Niektórzy mogą uważać, że zrozumienie listy ze skutkiem ubocznym nie jest dobrym rozwiązaniem. Oto alternatywa:
źródło
map
ze skutkiem ubocznym jest jeszcze bardziej mylące niż lista porównująca ze skutkiem ubocznym. Ponadto,lambda x: unique_list.append(x)
jest tylko clunkier i wolniejszy sposób przekazaćunique_list.append
.Wszystkie podejścia do utrzymywania porządku, które do tej pory widziałem, wykorzystują albo naiwne porównanie (w najlepszym razie złożoności czasowej O (n ^ 2)), albo kombinacje ciężkie
OrderedDicts
/set
+,list
które są ograniczone do możliwych do wprowadzenia wartości. Oto niezależne od skrótów rozwiązanie O (nlogn):Aktualizacja dodała
key
argument, dokumentację i zgodność z Python 3.źródło
tuple()
listy i ich haszowanie. | | | | - Ogólnie rzecz biorąc, proces mieszania zajmuje czas proporcjonalny do wielkości całych danych, podczas gdy to rozwiązanie zajmuje czas O (nlog (n)), zależnie tylko od długości listy.reduce()
Pracuje już nad posortowanej kolekcjisrt_enum
, dlaczego zastosowaćsorted
ponownie?Jeśli chcesz zachować porządek i nie używać żadnych modułów zewnętrznych, możesz to zrobić w prosty sposób:
Uwaga: Ta metoda zachowuje kolejność pojawiania się, więc, jak pokazano powyżej, dziewięć pojawi się po jednym, ponieważ był to pierwszy raz, gdy się pojawił. Jest to jednak taki sam wynik, jak w przypadku robienia
ale jest znacznie krótszy i działa szybciej.
Działa to, ponieważ za każdym razem, gdy
fromkeys
funkcja próbuje utworzyć nowy klucz, jeśli wartość już istnieje, po prostu ją zastąpi. Nie ma to jednakfromkeys
żadnego wpływu na słownik, ponieważ tworzy słownik, w którym wszystkie klucze mają wartośćNone
, więc w ten sposób skutecznie eliminuje wszystkie duplikaty.źródło
Możesz także to zrobić:
Powodem tego jest to, że
index
metoda zwraca tylko pierwszy indeks elementu. Zduplikowane elementy mają wyższe wskaźniki. Zobacz tutaj :źródło
list.index
jest operacją w czasie liniowym, dzięki czemu Twoje rozwiązanie jest kwadratowe.Spróbuj użyć zestawów:
źródło
Zredukuj wariant z zamówieniem zachowaj:
Załóżmy, że mamy listę:
Zredukuj wariant (nieefektywny):
5 x szybszy, ale bardziej wyrafinowany
Wyjaśnienie:
źródło
Najlepszym podejściem do usuwania duplikatów z listy jest użycie funkcji set () dostępnej w Pythonie, ponownie konwertując ten zestaw na listę
źródło
Możesz użyć następującej funkcji:
Przykład :
Stosowanie:
[„this”, „is”, „a”, „list”, „with”, „duplicates”, „in”, „the”]
źródło
Istnieje wiele innych odpowiedzi sugerujących różne sposoby na zrobienie tego, ale wszystkie są operacjami wsadowymi, a niektóre z nich odrzucają oryginalne zamówienie. Może to być w porządku w zależności od potrzeb, ale jeśli chcesz iterować wartości w kolejności pierwszej instancji każdej wartości i chcesz usunąć duplikaty w locie w porównaniu do wszystkich naraz, możesz użyć ten generator:
Zwraca generator / iterator, dzięki czemu można go używać w dowolnym miejscu, w którym można użyć iteratora.
Wynik:
Jeśli chcesz
list
, możesz to zrobić:Wynik:
źródło
seen = set(iterable); for item in seen: yield item
jest prawie na pewno szybszy. (Nie próbowałem tego konkretnego przypadku, ale tak sądzę.)Bez użycia zestawu
źródło
Możesz użyć
set
do usunięcia duplikatów:Pamiętaj jednak, że wyniki będą nieuporządkowane. Jeśli to jest problem:
źródło
Jeszcze jednym lepszym podejściem może być
i porządek pozostaje zachowany.
źródło
Ten dba o zamówienie bez większych problemów (OrderdDict i inni). Prawdopodobnie nie jest to metoda najbardziej Pythońska, ani najkrótsza, ale polega na tym:
źródło
list
); 2. Twoja metoda skaluje się bardzo źle: jest kwadratowa pod względem liczby elementówlist
.poniższy kod jest prosty do usunięcia duplikatu z listy
zwraca [1,2,3,4]
źródło
list(set(..))
(ponad 1 milion podań) pobije to rozwiązanie o około 10 pełnych sekund - podczas gdy takie podejście zajmuje około 12 sekund,list(set(..))
zajmuje tylko około 2 sekund!Oto najszybsze rozwiązanie python w porównaniu do innych wymienionych w odpowiedziach.
Wykorzystanie szczegółów implementacji oceny zwarć pozwala na użycie listowania, które jest wystarczająco szybkie.
visited.add(item)
zawsze zwracaNone
wynik, który jest oceniany jakoFalse
, więc prawa stronaor
zawsze będzie wynikiem takiego wyrażenia.Czas sam
źródło
Za pomocą zestawu :
Używając unikalnego :
źródło
Niestety. Większość odpowiedzi tutaj albo nie zachowuje kolejności, albo jest za długa. Oto prosta, zachowująca porządek odpowiedź.
To da ci x z usuniętymi duplikatami, ale zachowując kolejność.
źródło
Bardzo prosty sposób w Pythonie 3:
źródło
sorted(list(...))
jest redundantny (sorted
już domyślnie przekształca swój argument na nowylist
, sortuje go, a następnie zwraca nowylist
, więc używając obu środków, czyniąc niepotrzebne tymczasowelist
). Używaj tylkolist
wtedy, gdy wynik nie musi być sortowany, używaj tylkosorted
wtedy, gdy wynik wymaga sortowania.Magia wbudowanego typu Python
W Pythonie bardzo łatwo jest przetwarzać tak skomplikowane przypadki, jak i tylko przy użyciu wbudowanego typu python.
Pokażę ci, jak to zrobić!
Metoda 1: Przypadek ogólny
Sposób ( 1 kod wiersza ), aby usunąć zduplikowany element z listy i nadal zachować porządek sortowania
Otrzymasz wynik
Metoda 2: Przypadek specjalny
Specjalny przypadek przetwarzania nieukończonego ( 3 kody linii )
Otrzymasz wynik:
Ponieważ krotka jest haszowalna i możesz łatwo konwertować dane między listą a krotką
źródło