Jak usunąć duplikaty z listy przy zachowaniu porządku?

Czy istnieje wbudowana funkcja, która usuwa duplikaty z listy w Pythonie, zachowując porządek? Wiem, że mogę użyć zestawu do usuwania duplikatów, ale to niszczy pierwotną kolejność. Wiem też, że sam mogę tak toczyć:

def uniq(input):
  output = []
  for x in input:
    if x not in output:
      output.append(x)
  return output

(dzięki rozwiń dla tego próbki kodu.)

Ale chciałbym skorzystać z wbudowanego lub bardziej Pythonicznego idiomu, jeśli to możliwe.

Powiązane pytanie: w Pythonie jaki jest najszybszy algorytm do usuwania duplikatów z listy tak, aby wszystkie elementy były unikalne przy zachowaniu porządku?

Author: martineau, 2009-01-26

30 answers

Tutaj masz kilka alternatyw: http://www.peterbe.com/plog/uniqifiers-benchmark

Najszybszy:

def f7(seq):
    seen = set()
    seen_add = seen.add
    return [x for x in seq if not (x in seen or seen_add(x))]

Po co przypisywać seen.add do seen_add zamiast po prostu wywoływać seen.add? Python jest językiem dynamicznym, a rozwiązywanie seen.add każdej iteracji jest bardziej kosztowne niż rozwiązywanie zmiennej lokalnej. seen.add mogło się zmieniać między iteracjami, a środowisko uruchomieniowe nie jest wystarczająco inteligentne, aby to wykluczyć. Aby grać bezpiecznie, musi za każdym razem sprawdzać obiekt.

Jeśli planujesz korzystanie z tej funkcji dużo na tym samym zbiorze danych, być może lepiej byłoby z uporządkowanym zestawem: http://code.activestate.com/recipes/528878/

o(1) wstawianie, usuwanie i sprawdzanie członków dla każdej operacji.

(mała dodatkowa uwaga: seen.add() zawsze zwraca None, więc or powyżej znajduje się tylko jako sposób na próbę aktualizacji zestawu, a nie jako integralna część testu logicznego.)

 804
Author: Markus Jarderot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-05-25 08:35:54

Edit 2020

[28]}od CPython/PyPy 3.6 (i jako gwarancja językowa w 3.7), zwykły dict jest uporządkowany i jeszcze bardziej wydajny niż (również c zaimplementowany) collections.OrderedDict. Tak więc najszybsze rozwiązanie, zdecydowanie, jest również najprostsze:
>>> items = [1, 2, 0, 1, 3, 2]
>>> list(dict.fromkeys(items))
[1, 2, 0, 3]

Podobnie jak list(set(items))to przesuwa całą pracę do warstwy C (na Cpythonie), ale ponieważ dict S są uporządkowane, dict.fromkeys nie traci kolejności. Jest wolniejszy niż list(set(items)) (zwykle trwa 50-100% dłużej), ale znacznie szybszy niż każde inne rozwiązanie zachowujące porządek (zajmuje około połowę czasu hacków obejmujących użycie sets W listcomp).

Edycja 2016

Jak zauważył Raymond , w Pythonie 3.5+, gdzie OrderedDict jest zaimplementowane w C, podejście do rozumienia listy będzie wolniejsze niż OrderedDict (chyba że faktycznie potrzebujesz listy na końcu - a nawet wtedy, tylko jeśli wejście jest bardzo krótkie). Więc najlepszym rozwiązaniem dla 3,5+ jest OrderedDict.

Ważna Edycja 2015

As @abarnert notes, the more_itertools library (pip install more_itertools) zawiera unique_everseen funkcja, która jest zbudowana, aby rozwiązać ten problem bez nieczytelne (not seen.add) mutacje w zestawieniu list. Jest to również najszybsze rozwiązanie: {]}

>>> from  more_itertools import unique_everseen
>>> items = [1, 2, 0, 1, 3, 2]
>>> list(unique_everseen(items))
[1, 2, 0, 3]

Tylko jeden prosty import biblioteki i żadnych hacków. Wynika to z implementacji receptury itertoolsunique_everseen który wygląda tak:

def unique_everseen(iterable, key=None):
    "List unique elements, preserving order. Remember all elements ever seen."
    # unique_everseen('AAAABBBCCDAABBB') --> A B C D
    # unique_everseen('ABBCcAD', str.lower) --> A B C D
    seen = set()
    seen_add = seen.add
    if key is None:
        for element in filterfalse(seen.__contains__, iterable):
            seen_add(element)
            yield element
    else:
        for element in iterable:
            k = key(element)
            if k not in seen:
                seen_add(k)
                yield element

W Pythonie 2.7+ przyjęty wspólny idiom (który działa, ale nie jest zoptymalizowany pod kątem szybkości, użyłbym terazunique_everseen) do tego zastosowania collections.OrderedDict:

Runtime: O (N)

>>> from collections import OrderedDict
>>> items = [1, 2, 0, 1, 3, 2]
>>> list(OrderedDict.fromkeys(items))
[1, 2, 0, 3]

To wygląda o wiele ładniej niż:

seen = set()
[x for x in seq if x not in seen and not seen.add(x)]

I nie używa brzydkiego hacka:

not seen.add(x)

, która opiera się na fakcie, że set.add jest metodą in-place, która zawsze zwraca None, więc not None ewaluuje do True.

Zauważ jednak, że rozwiązanie hack jest szybsze w prędkość surowa, choć ma tę samą złożoność runtime O (N).

 401
Author: jamylak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-10 03:28:00

W CPython 3.6+ (i wszystkie inne implementacje Pythona zaczynające się od Python 3.7 + ), słowniki są uporządkowane , więc sposobem na usunięcie duplikatów z iterowalnego przy zachowaniu pierwotnej kolejności jest:

>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']

W Pythonie 3.5 i poniżej (w tym Python 2.7), użyj OrderedDict. Moje timingi pokazują, że jest to teraz najszybsze i najkrótsze z różnych podejść do Pythona 3.5.

>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
 135
Author: Raymond Hettinger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-09 23:01:41
sequence = ['1', '2', '3', '3', '6', '4', '5', '6']
unique = []
[unique.append(item) for item in sequence if item not in unique]

Unique → ['1', '2', '3', '6', '4', '5']

 41
Author: dansalmo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-02 04:11:32

Nie kopać martwego konia (to pytanie jest bardzo stare i ma już wiele dobrych odpowiedzi), ale oto rozwiązanie z wykorzystaniem pand, które jest dość szybkie w wielu okolicznościach i jest śmiertelnie proste w użyciu.

import pandas as pd

my_list = [0, 1, 2, 3, 4, 1, 2, 3, 5]

>>> pd.Series(my_list).drop_duplicates().tolist()
# Output:
# [0, 1, 2, 3, 4, 5]
 40
Author: Alexander,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-12-07 19:32:47

W językuPython 3.7 i wyżej, słowniki majązagwarantowane , Aby zapamiętać ich kluczową kolejność wstawiania. Odpowiedź na to pytanie podsumowuje obecny stan rzeczy.

Rozwiązanie OrderedDict staje się więc przestarzałe i bez żadnych instrukcji importu możemy po prostu wydać:

>>> lst = [1, 2, 1, 3, 3, 2, 4]
>>> list(dict.fromkeys(lst))
[1, 2, 3, 4]
 35
Author: timgeb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-11-17 11:38:06
from itertools import groupby
[ key for key,_ in groupby(sortedList)]

Lista nie musi być nawet sortowana , wystarczającym warunkiem jest pogrupowanie równych wartości.

Edit: założyłem, że "zachowanie porządku" oznacza, że lista jest rzeczywiście uporządkowana. Jeśli tak nie jest, to rozwiązanie MizardX jest właściwe.

Edycja społecznościowa: jest to jednak najbardziej elegancki sposób na "kompresję duplikatów kolejnych elementów w jeden element".

 27
Author: Rafał Dowgird,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-13 22:45:47

Myślę, że jeśli chcesz utrzymać porządek,

Możesz spróbować tego:

list1 = ['b','c','d','b','c','a','a']    
list2 = list(set(list1))    
list2.sort(key=list1.index)    
print list2

Lub podobnie możesz to zrobić:

list1 = ['b','c','d','b','c','a','a']  
list2 = sorted(set(list1),key=list1.index)  
print list2 
Możesz też to zrobić:
list1 = ['b','c','d','b','c','a','a']    
list2 = []    
for i in list1:    
    if not i in list2:  
        list2.append(i)`    
print list2

Można też zapisać tak:

list1 = ['b','c','d','b','c','a','a']    
list2 = []    
[list2.append(i) for i in list1 if not i in list2]    
print list2 
 25
Author: shamrock,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-27 21:37:23

Wystarczy dodać kolejną (bardzo wydajną) implementację takiej funkcjonalności z zewnętrznego modułu1: iteration_utilities.unique_everseen:

>>> from iteration_utilities import unique_everseen
>>> lst = [1,1,1,2,3,2,2,2,1,3,4]

>>> list(unique_everseen(lst))
[1, 2, 3, 4]

Timings

Zrobiłem kilka timingów (Python 3.6) i pokazują one, że jest szybszy niż wszystkie inne alternatywy, które testowałem, w tym OrderedDict.fromkeys, f7 i more_itertools.unique_everseen:

%matplotlib notebook

from iteration_utilities import unique_everseen
from collections import OrderedDict
from more_itertools import unique_everseen as mi_unique_everseen

def f7(seq):
    seen = set()
    seen_add = seen.add
    return [x for x in seq if not (x in seen or seen_add(x))]

def iteration_utilities_unique_everseen(seq):
    return list(unique_everseen(seq))

def more_itertools_unique_everseen(seq):
    return list(mi_unique_everseen(seq))

def odict(seq):
    return list(OrderedDict.fromkeys(seq))

from simple_benchmark import benchmark

b = benchmark([f7, iteration_utilities_unique_everseen, more_itertools_unique_everseen, odict],
              {2**i: list(range(2**i)) for i in range(1, 20)},
              'list size (no duplicates)')
b.plot()

Tutaj wpisz opis obrazka

I tylko, aby upewnić się, że zrobiłem test z większą ilością duplikatów tylko, aby sprawdzić, czy to sprawia, że różnica:

import random

b = benchmark([f7, iteration_utilities_unique_everseen, more_itertools_unique_everseen, odict],
              {2**i: [random.randint(0, 2**(i-1)) for _ in range(2**i)] for i in range(1, 20)},
              'list size (lots of duplicates)')
b.plot()

Tutaj wpisz opis obrazka

I jeden zawierający tylko jedną wartość:

b = benchmark([f7, iteration_utilities_unique_everseen, more_itertools_unique_everseen, odict],
              {2**i: [1]*(2**i) for i in range(1, 20)},
              'list size (only duplicates)')
b.plot()

Tutaj wpisz opis obrazka

We wszystkich tych przypadkach funkcja iteration_utilities.unique_everseen jest najszybsza (na moim komputerze).


Ta funkcja iteration_utilities.unique_everseen może również obsługiwać wartości niehaszowalne w danych wejściowych (jednak z wydajnością O(n*n) zamiast wydajności O(n), gdy wartości są hashable).

>>> lst = [{1}, {1}, {2}, {1}, {3}]

>>> list(unique_everseen(lst))
[{1}, {2}, {3}]

1 Zastrzeżenie: jestem autorem tego paczka.

 14
Author: MSeifert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-09 21:16:10

Za kolejną bardzo późną odpowiedź na kolejne bardzo stare pytanie:

The itertools receptury mają funkcję, która to robi, używając techniki set seen, ale:

  • obsługuje standardową funkcję key.
  • nie używa niestosownych hacków.
  • optymalizuje pętlę przez wstępne Wiązanie seen.add zamiast sprawdzania jej N razy. (f7 robi to również, ale niektóre wersje tak nie robią.)
  • optymalizuje pętlę za pomocą ifilterfalse, więc musisz tylko zapętlić unikalny elementy w Pythonie, zamiast wszystkich. (Oczywiście wciąż powtarzasz je wszystkie wewnątrz ifilterfalse, ale to jest w C i znacznie szybciej.)

Czy rzeczywiście jest szybszy niż f7? To zależy od Twoich danych, więc będziesz musiał je przetestować i zobaczyć. Jeśli na końcu chcesz mieć listę, f7 używa listcomp, a tutaj nie ma na to sposobu. (Możesz bezpośrednio append zamiast yield ing, lub możesz wprowadzić generator do funkcji list, ale żadna nie może być tak szybka jak LIST_APPEND wewnątrz listcomp.) W każdym razie Zwykle wyciskanie kilku mikrosekund nie będzie tak ważne, jak posiadanie łatwo zrozumiałej, wielokrotnego użytku, już napisanej funkcji, która nie wymaga DSU, gdy chcesz ozdobić.

Podobnie jak w przypadku wszystkich przepisów, jest również dostępny w more-iterools.

Jeśli chcesz tylko przypadek no-key, możesz uprościć go jako:

def unique(iterable):
    seen = set()
    seen_add = seen.add
    for element in itertools.ifilterfalse(seen.__contains__, iterable):
        seen_add(element)
        yield element
 12
Author: abarnert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-09 18:33:02

Dla typów hashable (np. lista list), na podstawie MizardX'a:

def f7_noHash(seq)
    seen = set()
    return [ x for x in seq if str( x ) not in seen and not seen.add( str( x ) )]
 6
Author: zmk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-21 20:04:12

5 X szybsza redukcja wariantu, ale bardziej wyrafinowana

>>> l = [5, 6, 6, 1, 1, 2, 2, 3, 4]
>>> reduce(lambda r, v: v in r[1] and r or (r[0].append(v) or r[1].add(v)) or r, l, ([], set()))[0]
[5, 6, 1, 2, 3, 4]

Wyjaśnienie:

default = (list(), set())
# use list to keep order
# use set to make lookup faster

def reducer(result, item):
    if item not in result[1]:
        result[0].append(item)
        result[1].add(item)
    return result

>>> reduce(reducer, l, default)[0]
[5, 6, 1, 2, 3, 4]
 4
Author: Sergey M Nikitin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-28 06:39:15

Oto prosty sposób na to:

list1 = ["hello", " ", "w", "o", "r", "l", "d"]
sorted(set(list1 ), key=lambda x:list1.index(x))

Co daje wyjście:

["hello", " ", "w", "o", "r", "l", "d"]
 4
Author: Ahmed4end,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-20 15:37:43

Użytkownicy Pandas powinni sprawdzić pandas.unique.

>>> import pandas as pd
>>> lst = [1, 2, 1, 3, 3, 2, 4]
>>> pd.unique(lst)
array([1, 2, 3, 4])

Funkcja zwraca tablicę NumPy. W razie potrzeby można go przekonwertować na listę z tolist metoda.

 4
Author: timgeb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-26 09:30:14

Zapożyczając ideę rekurencyjną używaną w definiowaniu funkcji Haskella nub dla list, byłoby to podejście rekurencyjne:

def unique(lst):
    return [] if lst==[] else [lst[0]] + unique(filter(lambda x: x!= lst[0], lst[1:]))

Np.:

In [118]: unique([1,5,1,1,4,3,4])
Out[118]: [1, 5, 4, 3]

Próbowałem go dla rosnących rozmiarów danych i widziałem sublinearną złożoność czasową(nie definitywną ,ale sugeruje, że powinno to być dobre dla normalnych danych).

In [122]: %timeit unique(np.random.randint(5, size=(1)))
10000 loops, best of 3: 25.3 us per loop

In [123]: %timeit unique(np.random.randint(5, size=(10)))
10000 loops, best of 3: 42.9 us per loop

In [124]: %timeit unique(np.random.randint(5, size=(100)))
10000 loops, best of 3: 132 us per loop

In [125]: %timeit unique(np.random.randint(5, size=(1000)))
1000 loops, best of 3: 1.05 ms per loop

In [126]: %timeit unique(np.random.randint(5, size=(10000)))
100 loops, best of 3: 11 ms per loop

Myślę również, że to interesujące, że można to łatwo uogólnić do wyjątkowości przez inne operacje. Tak:

import operator
def unique(lst, cmp_op=operator.ne):
    return [] if lst==[] else [lst[0]] + unique(filter(lambda x: cmp_op(x, lst[0]), lst[1:]), cmp_op)

Na przykład można przekazać funkcję to używa pojęcia zaokrąglenia do tej samej liczby całkowitej, jak gdyby było "równością" dla celów unikalności, jak to:

def test_round(x,y):
    return round(x) != round(y)

Wtedy unique (some_list, test_round) dostarczy unikalnych elementów listy, gdzie wyjątkowość nie oznacza już tradycyjnej równości (co jest implikowane przez użycie jakiegokolwiek podejścia do tego problemu opartego na zestawie lub kluczu dict), ale zamiast tego oznacza tylko pierwszy element, który zaokrągla do K dla każdej możliwej liczby całkowitej K, że elementy mogą zaokrąglać do K, np.:

In [6]: unique([1.2, 5, 1.9, 1.1, 4.2, 3, 4.8], test_round)
Out[6]: [1.2, 5, 1.9, 4.2, 3]
 3
Author: ely,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-11 14:29:55

Możesz odwołać się do zrozumienia listy, ponieważ jest ona budowana za pomocą symbolu " _[1]".
na przykład następująca funkcja unique-wyświetla listę elementów bez zmiany ich kolejności poprzez odwoływanie się do jej listy.

def unique(my_list): 
    return [x for x in my_list if x not in locals()['_[1]']]

Demo:

l1 = [1, 2, 3, 4, 1, 2, 3, 4, 5]
l2 = [x for x in l1 if x not in locals()['_[1]']]
print l2

Wyjście:

[1, 2, 3, 4, 5]
 3
Author: Zhifeng Hu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-08 22:40:37

ODPOWIEDŹ Mizardxa daje dobry zbiór wielu podejść.

To właśnie wymyśliłem myśląc głośno:

mylist = [x for i,x in enumerate(mylist) if x not in mylist[i+1:]]
 2
Author: Saurabh Hirani,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-28 12:17:04

Mógłbyś zrobić coś w rodzaju brzydkiej listy.

[l[i] for i in range(len(l)) if l.index(l[i]) == i]
 1
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-25 01:28:31

Relatywnie skuteczne podejście z _sorted_ a numpy tablicami:

b = np.array([1,3,3, 8, 12, 12,12])    
numpy.hstack([b[0], [x[0] for x in zip(b[1:], b[:-1]) if x[0]!=x[1]]])

Wyjścia:

array([ 1,  3,  8, 12])
 1
Author: dominecf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-25 06:11:19
l = [1,2,2,3,3,...]
n = []
n.extend(ele for ele in l if ele not in set(n))

Wyrażenie generatora, które używa o(1) look up zbioru w celu określenia, czy element ma być dołączony do nowej listy.

 1
Author: kylieCatt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-07 05:02:54

Proste rozwiązanie rekurencyjne:

def uniquefy_list(a):
    return uniquefy_list(a[1:]) if a[0] in a[1:] else [a[0]]+uniquefy_list(a[1:]) if len(a)>1 else [a[0]]
 1
Author: Ilya Prokin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-16 23:05:08

Eliminowanie zduplikowanych wartości w sekwencji, ale zachowanie kolejności pozostałych elementów. Wykorzystanie funkcji generatora ogólnego przeznaczenia.

# for hashable sequence
def remove_duplicates(items):
    seen = set()
    for item in items:
        if item not in seen:
            yield item
            seen.add(item)

a = [1, 5, 2, 1, 9, 1, 5, 10]
list(remove_duplicates(a))
# [1, 5, 2, 9, 10]



# for unhashable sequence
def remove_duplicates(items, key=None):
    seen = set()
    for item in items:
        val = item if key is None else key(item)
        if val not in seen:
            yield item
            seen.add(val)

a = [ {'x': 1, 'y': 2}, {'x': 1, 'y': 3}, {'x': 1, 'y': 2}, {'x': 2, 'y': 4}]
list(remove_duplicates(a, key=lambda d: (d['x'],d['y'])))
# [{'x': 1, 'y': 2}, {'x': 1, 'y': 3}, {'x': 2, 'y': 4}]
 1
Author: Srivastava,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-05-28 09:32:13

Jeśli potrzebujesz jednego linera to może to pomoże:

reduce(lambda x, y: x + y if y[0] not in x else x, map(lambda x: [x],lst))

... powinno działać, ale popraw mnie jeśli się mylę

 0
Author: code22,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-05 17:06:25

Jeśli rutynowo używasz pandas, i estetyka jest preferowana niż wydajność, rozważ wbudowaną funkcję pandas.Series.drop_duplicates:

    import pandas as pd
    import numpy as np

    uniquifier = lambda alist: pd.Series(alist).drop_duplicates().tolist()

    # from the chosen answer 
    def f7(seq):
        seen = set()
        seen_add = seen.add
        return [ x for x in seq if not (x in seen or seen_add(x))]

    alist = np.random.randint(low=0, high=1000, size=10000).tolist()

    print uniquifier(alist) == f7(alist)  # True

Czas:

    In [104]: %timeit f7(alist)
    1000 loops, best of 3: 1.3 ms per loop
    In [110]: %timeit uniquifier(alist)
    100 loops, best of 3: 4.39 ms per loop
 0
Author: Lei,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-18 00:20:54

To zachowa porządek i będzie działać w czasie O (n). zasadniczo chodzi o to, aby stworzyć dziurę wszędzie tam, gdzie znajduje się duplikat i zatopić go na dno. wykorzystuje wskaźnik odczytu i zapisu. za każdym razem, gdy duplikat zostanie znaleziony, tylko wskaźnik odczytu przesuwa się, a wskaźnik zapisu pozostaje na zduplikowanym wpisie, aby go zastąpić.

def deduplicate(l):
    count = {}
    (read,write) = (0,0)
    while read < len(l):
        if l[read] in count:
            read += 1
            continue
        count[l[read]] = True
        l[write] = l[read]
        read += 1
        write += 1
    return l[0:write]
 0
Author: Soham Joshi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-12 17:16:19

Rozwiązanie bez użycia importowanych modułów lub zestawów:

text = "ask not what your country can do for you ask what you can do for your country"
sentence = text.split(" ")
noduplicates = [(sentence[i]) for i in range (0,len(sentence)) if sentence[i] not in sentence[:i]]
print(noduplicates)

Daje wyjście:

['ask', 'not', 'what', 'your', 'country', 'can', 'do', 'for', 'you']
 0
Author: Rob Murray,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-27 13:08:08

Metoda in-place

Ta metoda jest kwadratowa, ponieważ dla każdego elementu listy mamy linearne przeszukiwanie listy (do tego musimy dodać koszt przestawiania listy ze względu na del s).

To powiedziawszy, możliwe jest działanie w miejscu, jeśli zaczniemy od końca listy i przejdziemy w kierunku początku, usuwając każdy termin, który jest obecny na liście podrzędnej po jej lewej

Ten pomysł w kodzie jest po prostu

for i in range(len(l)-1,0,-1): 
    if l[i] in l[:i]: del l[i] 

prosty test realizacja

In [91]: from random import randint, seed                                                                                            
In [92]: seed('20080808') ; l = [randint(1,6) for _ in range(12)] # Beijing Olympics                                                                 
In [93]: for i in range(len(l)-1,0,-1): 
    ...:     print(l) 
    ...:     print(i, l[i], l[:i], end='') 
    ...:     if l[i] in l[:i]: 
    ...:          print( ': remove', l[i]) 
    ...:          del l[i] 
    ...:     else: 
    ...:          print() 
    ...: print(l)
[6, 5, 1, 4, 6, 1, 6, 2, 2, 4, 5, 2]
11 2 [6, 5, 1, 4, 6, 1, 6, 2, 2, 4, 5]: remove 2
[6, 5, 1, 4, 6, 1, 6, 2, 2, 4, 5]
10 5 [6, 5, 1, 4, 6, 1, 6, 2, 2, 4]: remove 5
[6, 5, 1, 4, 6, 1, 6, 2, 2, 4]
9 4 [6, 5, 1, 4, 6, 1, 6, 2, 2]: remove 4
[6, 5, 1, 4, 6, 1, 6, 2, 2]
8 2 [6, 5, 1, 4, 6, 1, 6, 2]: remove 2
[6, 5, 1, 4, 6, 1, 6, 2]
7 2 [6, 5, 1, 4, 6, 1, 6]
[6, 5, 1, 4, 6, 1, 6, 2]
6 6 [6, 5, 1, 4, 6, 1]: remove 6
[6, 5, 1, 4, 6, 1, 2]
5 1 [6, 5, 1, 4, 6]: remove 1
[6, 5, 1, 4, 6, 2]
4 6 [6, 5, 1, 4]: remove 6
[6, 5, 1, 4, 2]
3 4 [6, 5, 1]
[6, 5, 1, 4, 2]
2 1 [6, 5]
[6, 5, 1, 4, 2]
1 5 [6]
[6, 5, 1, 4, 2]

In [94]:                                                                                                                             
 0
Author: gboffi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-11-04 17:30:53

Podejście Zmk wykorzystuje zrozumienie listy, które jest bardzo szybkie, ale zachowuje porządek w sposób naturalny. W celu zastosowania do łańcuchów uwzględniających wielkość liter można je łatwo modyfikować. To również zachowuje oryginalną obudowę.

def DelDupes(aseq) :
    seen = set()
    return [x for x in aseq if (x.lower() not in seen) and (not seen.add(x.lower()))]

Ściśle powiązane funkcje to:

def HasDupes(aseq) :
    s = set()
    return any(((x.lower() in s) or s.add(x.lower())) for x in aseq)

def GetDupes(aseq) :
    s = set()
    return set(x for x in aseq if ((x.lower() in s) or s.add(x.lower())))
 0
Author: Hewey Dewey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-27 14:01:30

Kredyt dla @ wjandrea za dict.idea metody fromdict:

def solve(arr): 
    return list(dict.fromkeys(arr[::-1]))[::-1]

To odwróci wejście i wyjście, aby poprawnie iterację

 0
Author: Vedant Mehta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-18 02:05:59
x = [1, 2, 1, 3, 1, 4]

# brute force method
arr = []
for i in x:
  if not i in arr:
    arr.insert(x[i],i)

# recursive method
tmp = []
def remove_duplicates(j=0):
    if j < len(x):
      if not x[j] in tmp:
        tmp.append(x[j])
      i = j+1  
      remove_duplicates(i)

      

remove_duplicates()
 0
Author: Franco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-23 04:29:47