Jak znaleźć duplikaty na liście Python i utworzyć kolejną listę duplikatów? Lista zawiera tylko liczby całkowite.
python
list
duplicates
MFB
źródło
źródło
Odpowiedzi:
Aby usunąć duplikaty, użyj
set(a)
. Aby wydrukować duplikaty, coś takiego:Pamiętaj, że
Counter
nie jest to szczególnie wydajne ( czasy ) i prawdopodobnie przesada tutaj.set
będzie działać lepiej. Ten kod oblicza listę unikalnych elementów w kolejności źródłowej:lub bardziej zwięźle:
Nie polecam tego drugiego stylu, ponieważ nie jest oczywiste, co
not seen.add(x)
się dzieje (add()
metoda set zawsze powracaNone
, stąd potrzebanot
).Aby obliczyć listę zduplikowanych elementów bez bibliotek:
Jeśli elementy listy nie są haszowalne, nie możesz używać zestawów / dykt i musisz uciekać się do kwadratowego rozwiązania czasowego (porównaj każdy z nich). Na przykład:
źródło
O(n)
, ponieważ iteruje listę tylko raz i ustawia wyszukiwaniaO(1)
.dup = []
else: dup.append(x)
print()
seen = set()
następniedupe = set(x for x in a if x in seen or seen.add(x))
źródło
l
goset(l)
tylko zmniejsza złożoność czasu najgorszego przypadku, a zatem nie robi nic, aby rozwiązać problemy związane z wydajnością na większą skalę dzięki tej odpowiedzi. To chyba nie było takie proste. Krótko mówiąc, nie rób tego.Nie potrzebujesz liczenia, tylko czy przedmiot był wcześniej widziany. Dostosowałem tę odpowiedź do tego problemu:
Na wszelki wypadek liczy się prędkość:
Oto wyniki: (dobra robota @JohnLaRooy!)
Co ciekawe, oprócz samego taktowania, również ranking zmienia się nieznacznie, gdy używany jest pypy. Co najciekawsze, podejście oparte na licznikach czerpie ogromne korzyści z optymalizacji pypy, podczas gdy podejście buforowania metod, które zasugerowałem, wydaje się prawie nie mieć żadnego efektu.
Widocznie ten efekt jest związany z „duplikacją” danych wejściowych. Ustawiłem
l = [random.randrange(1000000) for i in xrange(10000)]
i otrzymałem te wyniki:źródło
add
każdym razem, gdy konieczne będzie wstawienie.pypy
jeśli masz go pod ręką i idziesz na szybkość.Możesz użyć
iteration_utilities.duplicates
:lub jeśli chcesz tylko jeden z każdego duplikatu, można to połączyć z
iteration_utilities.unique_everseen
:Może także obsługiwać elementy niewymagalne (jednak kosztem wydajności):
Jest to coś, z czym poradzi sobie tylko kilka innych podejść.
Benchmarki
Zrobiłem szybki test porównawczy zawierający większość (ale nie wszystkie) wymienionych tu podejść.
Pierwszy test porównawczy obejmował tylko niewielki zakres długości list, ponieważ niektóre podejścia mają
O(n**2)
zachowanie.Na wykresach oś y reprezentuje czas, więc niższa wartość oznacza lepiej. Jest także wykreślany log-log, dzięki czemu można lepiej wizualizować szeroki zakres wartości:
Usuwając
O(n**2)
podejścia, wykonałem kolejny test porównawczy do pół miliona elementów na liście:Jak widać,
iteration_utilities.duplicates
podejście jest szybsze niż w przypadku innych podejść, a nawet tworzenie łańcuchówunique_everseen(duplicates(...))
było szybsze lub równie szybkie niż w przypadku innych podejść.Jedną dodatkową interesującą rzeczą, którą należy tutaj zauważyć, jest to, że podejścia do pand są bardzo wolne dla małych list, ale mogą z łatwością konkurować o dłuższe listy.
Jednak ponieważ te testy porównawcze pokazują, że większość podejść działa mniej więcej równo, więc nie ma znaczenia, które z nich zostanie użyte (z wyjątkiem 3, które miały
O(n**2)
czas działania).Benchmark 1
Benchmark 2
Zrzeczenie się
1 Jest to z biblioteki trzeciej mam napisane:
iteration_utilities
.źródło
Natknąłem się na to pytanie, patrząc na coś powiązanego - i zastanawiam się, dlaczego nikt nie zaoferował rozwiązania opartego na generatorze? Rozwiązaniem tego problemu byłoby:
Martwiłem się o skalowalność, dlatego przetestowałem kilka podejść, w tym naiwne elementy, które działają dobrze na małych listach, ale skalują się strasznie, gdy listy stają się większe (uwaga - lepiej byłoby użyć timeit, ale jest to przykładowe).
Do porównania dołączyłem @moooeeeep (jest imponująco szybki: najszybszy, jeśli lista wejściowa jest całkowicie losowa) i podejście itertools, które jest jeszcze szybsze dla najczęściej posortowanych list ... Teraz obejmuje podejście pandy z @firelynx - wolno, ale nie okropnie i proste. Uwaga - podejście sort / tee / zip jest konsekwentnie najszybsze na mojej maszynie w przypadku dużych, najczęściej uporządkowanych list, moooeeeep jest najszybszy w przypadku list losowych, ale przebieg może się różnić.
Zalety
Założenia
Najszybsze rozwiązanie, 1 milion wpisów:
Podejścia przetestowane
Wyniki testu „wszystkie duplikaty” były spójne, znajdując „pierwszą” duplikat, a następnie „wszystkie” duplikaty w tej tablicy:
Kiedy listy są najpierw tasowane, cena tego rodzaju staje się widoczna - wydajność wyraźnie spada i dominuje podejście @moooeeeep, przy czym podejścia set & dict są podobne, ale wykonawca:
źródło
random.shuffle(c)
to uwzględnić. Ponadto nie mogę zreplikować twoich wyników podczas uruchamiania niezmienionego skryptu (zupełnie inna kolejność), więc może zależy to również od procesora.Korzystanie z pand:
źródło
collections.Counter jest nowy w Pythonie 2.7:
We wcześniejszej wersji można zamiast tego użyć konwencjonalnego słownika:
źródło
Oto schludne i zwięzłe rozwiązanie -
źródło
Bez konwersji na listę i prawdopodobnie najprostszym sposobem byłoby coś takiego jak poniżej. Może to być przydatne podczas wywiadu, gdy proszą o nieużywanie zestawów
======= else, aby uzyskać 2 osobne listy unikalnych wartości i zduplikowanych wartości
źródło
Zrobiłbym to z pandami, ponieważ często używam pand
Daje
Prawdopodobnie nie jest zbyt wydajny, ale z pewnością zawiera mniej kodu niż wiele innych odpowiedzi, więc pomyślałem, że mógłbym się przyłączyć
źródło
pda = pd.Series(a)
print list(pda[pda.duplicated()])
trzeci przykład zaakceptowanej odpowiedzi podaje błędną odpowiedź i nie próbuje duplikatów. Oto poprawna wersja:
źródło
A może po prostu przejdziemy przez każdy element na liście, sprawdzając liczbę wystąpień, a następnie dodając je do zestawu, który następnie wydrukuje duplikaty. Mam nadzieję, że to pomoże komuś tam.
źródło
Możemy użyć
itertools.groupby
, aby znaleźć wszystkie przedmioty, które mają duplikaty:Dane wyjściowe będą:
źródło
dupes = [x for x, y in groupby(sorted(myList)) if len(list(y)) > 1]
Myślę, że najbardziej skutecznym sposobem na znalezienie duplikatów na liście jest:
Wykorzystuje
Counter
wszystkie elementy i wszystkie unikalne elementy. Odjęcie pierwszego od drugiego spowoduje pominięcie tylko duplikatów.źródło
Trochę późno, ale dla niektórych może być pomocny. W przypadku obszernej listy uznałem, że to zadziałało dla mnie.
Pokazuje tylko i wszystkie duplikaty i zachowuje porządek.
źródło
Bardzo prosty i szybki sposób znajdowania duplikatów za pomocą jednej iteracji w Pythonie to:
Dane wyjściowe będą następujące:
To i więcej w moim blogu http://www.howtoprogramwithpython.com
źródło
Wchodzę znacznie później w tę dyskusję. Mimo to chciałbym poradzić sobie z tym problemem za pomocą jednej wkładki. Ponieważ taki jest urok Pythona. jeśli chcemy po prostu przenieść duplikaty na osobną listę (lub dowolną kolekcję), sugeruję zrobienie tego jak poniżej. Powiedzmy, że mamy zduplikowaną listę, którą możemy nazwać „docelową”
Teraz, jeśli chcemy uzyskać duplikaty, możemy użyć jednej linijki, jak poniżej:
Ten kod umieści zduplikowane rekordy jako klucze i policzy jako wartość w słowniku „duplikaty”. Słownik „duplikatów” będzie wyglądał jak poniżej:
Jeśli chcesz tylko wszystkich rekordów zawierających same duplikaty na liście, jego kod jest znowu znacznie krótszy:
Dane wyjściowe będą:
Działa to doskonale w wersjach Python 2.7.x +
źródło
Jednowierszowy język Python 3.8, jeśli nie chcesz pisać własnego algorytmu lub korzystać z bibliotek:
Drukuje element i liczy:
groupby
przyjmuje funkcję grupowania, dzięki czemu można definiować grupy na różne sposoby i zwracać dodatkoweTuple
pola w razie potrzeby.groupby
jest leniwy, więc nie powinno być zbyt wolno.źródło
Niektóre inne testy. Oczywiście zrobić ...
... jest zbyt kosztowne. Jest około 500 razy szybszy (dłuższa tablica daje lepsze wyniki), aby zastosować następną metodę końcową:
Tylko 2 pętle, bez bardzo kosztownych
l.count()
operacji.Oto kod, na przykład, aby porównać metody. Kod znajduje się poniżej, oto wynik:
Kod testowy:
źródło
Metoda 1:
Wyjaśnienie: [val dla idx, val w wyliczeniu (lista_wejściowa), jeśli val w liście_wejściowej [idx + 1:]] jest zrozumieniem listy, która zwraca element, jeśli ten sam element jest obecny z bieżącej pozycji, na liście, indeks .
Przykład: lista_wejściowa = [42,31,42,31,3,31,31,5,6,6,6,6,6,6,7,42]
zaczynając od pierwszego elementu na liście, 42, o indeksie 0, sprawdza, czy element 42 jest obecny na liście_wejściowej [1:] (tj. od indeksu 1 do końca listy) Ponieważ 42 jest obecny na liście_wejściowej [1:] , zwróci 42.
Następnie przechodzi do następnego elementu 31 z indeksem 1 i sprawdza, czy element 31 jest obecny na liście_wejściowej [2:] (tj. Od indeksu 2 do końca listy), ponieważ 31 jest obecny na liście_wejściowej [2:], zwróci 31.
podobnie przechodzi przez wszystkie elementy na liście i zwraca tylko powtarzające się / zduplikowane elementy do listy.
Następnie, ponieważ mamy duplikaty, na liście musimy wybrać jeden z każdego duplikatu, tj. Usunąć duplikat między duplikatami, i aby to zrobić, wywołujemy wbudowany w Pythona zestaw o nazwie set (), który usuwa duplikaty,
Następnie pozostaje nam zestaw, ale nie lista, i dlatego do konwersji z zestawu na listę używamy, rzutowania czcionek, list (), i to konwertuje zestaw elementów na listę.
Metoda 2:
Objaśnienie: Tutaj tworzymy na początek dwie puste listy. Następnie przechodź dalej przez wszystkie elementy listy, aby sprawdzić, czy istnieje ona w temp_list (początkowo pusta). Jeśli nie ma go na liście temp, dodajemy go do listy temp, używając metody append .
Jeśli już istnieje w temp_list, oznacza to, że bieżący element listy jest duplikatem i dlatego musimy dodać go do dupe_list przy użyciu metody append .
źródło
Zasadniczo usuwasz duplikaty, konwertując na set (
clean_list
), a następnie iterujeszraw_list
, usuwając jeitem
z czystej listy pod kątem wystąpienia wraw_list
. Jeśliitem
nie zostanie znaleziony, zgłoszonyValueError
wyjątek zostanie przechwycony iitem
zostanie dodany doduplicated_items
listy.Jeśli potrzebny jest indeks zduplikowanych elementów, wystarczy
enumerate
lista i zabawa z indeksem. (for index, item in enumerate(raw_list):
), który jest szybszy i zoptymalizowany dla dużych list (takich jak tysiące + elementów)źródło
użycie
list.count()
metody na liście, aby znaleźć duplikaty elementów danej listyźródło
jedno-liniowy, dla zabawy i tam, gdzie wymagane jest jedno stwierdzenie.
źródło
źródło
Rozwiązanie jednoliniowe:
źródło
Tutaj jest wiele odpowiedzi, ale myślę, że jest to stosunkowo bardzo czytelne i łatwe do zrozumienia podejście:
Uwagi:
źródło
Oto szybki generator, który używa słownika do przechowywania każdego elementu jako klucza z wartością logiczną do sprawdzania, czy zduplikowany element został już wydany.
W przypadku list ze wszystkimi elementami typu skrótu:
W przypadku list, które mogą zawierać listy:
źródło
źródło
Podczas korzystania z toolz :
źródło
w ten sposób musiałem to zrobić, ponieważ rzuciłem sobie wyzwanie, aby nie używać innych metod:
więc twoja próbka działa jako:
źródło
duplist = list(set(a))
.