2009-08-16 10 views

Odpowiedz

6

Oto kolejny słownik zorientowany sposób:

l = [0, 1, 1, 2, 2] 
d = {} 
for i in l: d[i] = d.has_key(i) 

[k for k in d.keys() if not d[k]] 
+0

+1 Naprawdę ładne, gromadzi niewiele więcej informacji, niż potrzebujesz, aby rozwiązać zadanie. Możesz jednak pozbyć się '.keys()'. –

+0

Tak, .keys() jest całkowicie opcjonalnym, ale nieco bardziej czytelnym IMO. – mhawke

+0

ładne myślenie, ponieważ nie ma niepotrzebnych informacji, takich jak Alex, ale jest to w zasadzie to samo pojęcie, i nie będzie działać na przedmiotach, które nie są nieosiągalne. –

12

Musisz dwie pętle (lub równoważnie pętlę i listcomp, jak poniżej), ale nie te zagnieżdżone:

import collections 
d = collections.defaultdict(int) 
for x in L: d[x] += 1 
L[:] = [x for x in L if d[x] == 1] 

To rozwiązanie zakłada, że ​​elementy listy są hashable, czyli że są użyteczne jako indeksy w dyktach, zbiory zestawów itp.

OP wskazuje, że zależy im na TOŻSAMOŚCI obiektu, a nie WARTOŚCI (więc na przykład dwie podlisty o wartości [1,2,3, które są jednakowe, ale mogą nie być identyczne, nie uważane za duplikaty). Jeśli tak jest w istocie to ten kod jest użyteczny, wystarczy zastąpić d[x] z d[id(x)] w obu przypadkach i będzie pracować dla wszystkich typów obiektów w liście L.

Zmienne obiekty (wymienia, dicts, zestawy, ...) są zazwyczaj nie jest zgodny z haseł, dlatego nie można go używać w taki sposób. Obiekty zdefiniowane przez użytkownika są domyślnie hashable (z hash(x) == id(x)), chyba że ich klasa definiuje specjalne metody porównywania (__eq__, __cmp__, ...), w którym to przypadku są one dostępne tylko wtedy, gdy ich klasa również definiuje metodę __hash__.

Jeśli liĹ L's elementy nie są hashable, ale porównywalne do nierówności (a więc sortable), i nie dbają o ich kolejności w liście, można wykonać zadanie w czasie O(N log N) najpierw Sortowanie listę i zastosowanie itertools.groupby (prawie, ale nie całkiem w sposób sugerowany przez inną odpowiedź).

Inne podejścia, polegające na stopniowym zmniejszaniu wydajności i zwiększaniu ogólności, mogą radzić sobie z niezmiennymi sortownicami, gdy dbasz o pierwotne zamówienie listy (utwórz posortowaną kopię, a w drugiej pętli sprawdź powtórzenia na niej przy pomocy bisect - - także O (N log N), ale odrobinę wolniej) oraz z obiektami, których jedyną właściwością jest to, że są porównywalne dla równości (nie ma możliwości uniknięcia przerażającej wydajności O (N ** 2) w tym maksymalnie ogólnym przypadku) .

Jeśli OP może wyjaśnić, który przypadek dotyczy jego konkretnego problemu, chętnie pomogę (a zwłaszcza, jeśli obiekty w nim są AHQ, kod podany powyżej powinien wystarczyć ;-) .

+0

Nie Nie potrzebuję hasza Myślę, że to tylko duplikacja obiektów, które chciałem usunąć. (Nadal myślę w C, ale to, co chciałem powiedzieć powyżej, to to, że wskaźniki do obiektów będą takie same, więc nie ma potrzeby używania hasha - czy jest to ważne w landzie Python?) –

+0

Dlaczego napisałeś "L [:] = lista (zestaw (L)) "zamiast bardziej oczywiste (dla mnie)" L = lista (zestaw (L)) "? Wydaje się, że robią to samo, gdy próbuję ich w tłumaczu. Czy brakuje mi jakiegoś odcienia? Dzięki! – samtregar

+1

Drugie rozwiązanie nie wydaje się właściwe: usuwa duplikaty, ale problem polegał na usunięciu wszystkich duplikatów. –

9
[x for x in the_list if the_list.count(x)==1] 

Chociaż nadal jest to pętla zagnieżdżona za kulisami.

+0

Tak, O (N ** 2) (podczas gdy podejście nie-zagnieżdżone, które pokazuję, to O (N)). –

+0

Wydaje mi się, że wolę rozwiązanie Alexa, ponieważ sprawdza ono tylko listę dwukrotnie, twoje rozwiązanie to n^2. –

+0

WOW. Naprawdę muszę odejść czytając o zrozumieniu listy! Nadal staram się dowiedzieć, co dokładnie dzieje się powyżej. Ale dzięki bardzo sepp i Alex. –

4
>>> l = [0,1,1,2,2] 
>>> [x for x in l if l.count(x) is 1] 
[0] 
+0

Czy jest jakaś korzyść z używania 'jest' ponad' == '? Wiem, że 1 jest wystarczająco małym numerem, aby to działało, ale czy "jest" rzeczywiście szybsze przy porównywaniu liczb całkowitych? – Markus

+1

Nie powinieneś używać 'is' z liczbami, działa to tylko dlatego, że cpython optymalizuje niektóre często używane stałe (takie jak małe (<255) ints, 1.0, 0.0, puste krotki/zestawy itp.) I traktuje je jako single ... ale to nie jest częścią Pythona * język *. –

+0

Do ** not ** użyj 'is' podczas testowania równości wartości. To rozwiązanie jest podejściem złożoności O (N ** 2), ponieważ 'list.count()' wykonuje pełne skanowanie listy za każdym razem, gdy go wywołujesz, i nazywasz to N razy. –

3
l = [0,1,2,1,2] 
def justonce(l): 
    once = set() 
    more = set() 
    for x in l: 
     if x not in more: 
      if x in once: 
       more.add(x) 
       once.remove(x) 
      else: 
       once.add(x) 
    return once 

print justonce(l) 
+0

Konwertowanie z powrotem do listy byłoby miłe. – nilamo

+0

To nie zachowuje porządku, jak robi to Alex. –

4

W tym samym duchu jak roztwór Alexa można wykorzystać do Counter/MultiSet (zbudowany w recepturze 2.7, kompatybilnym z 2.5 i powyżej), aby zrobić to samo:

In [1]: from counter import Counter 

In [2]: L = [0, 1, 1, 2, 2] 

In [3]: multiset = Counter(L) 

In [4]: [x for x in L if multiset[x] == 1] 
Out[4]: [0] 
1

myślę, że rzeczywiste czasy są rodzajem interesujący:

Alex”odpowiedź:

python -m timeit -s "l = range(1,1000,2) + range(1,1000,3); import collections" "d = collections.defaultdict(int)" "for x in l: d[x] += 1" "l[:] = [x for x in l if d[x] == 1]" 
1000 loops, best of 3: 370 usec per loop 

Mine:

python -m timeit -s "l = range(1,1000,2) + range(1,1000,3)" "once = set()" "more = set()" "for x in l:" " if x not in more:" " if x in once:" " more.add(x)" " once.remove(x)" " else:" " once.add(x)" 
1000 loops, best of 3: 275 usec per loop 

wersja O (n ** 2) sepp2k, aby pokazać, dlaczego liczy się kompendium ;-)

python -m timeit -s "l = range(1,1000,2) + range(1,1000,3)" "[x for x in l if l.count(x)==1]" 
100 loops, best of 3: 16 msec per loop 

Roberta + klasyfikowane:

python -m timeit -s "l = range(1,1000,2) + range(1,1000,3); import itertools" "[elem[0] for elem in itertools.groupby(sorted(l)) if elem[1].next()== 0]" 
1000 loops, best of 3: 316 usec per loop 

mhawke użytkownika:

python -m timeit -s "l = range(1,1000,2) + range(1,1000,3)" "d = {}" "for i in l: d[i] = d.has_key(i)" "[k for k in d.keys() if not d[k]]" 
1000 loops, best of 3: 251 usec per loop 

Lubię ostatni, mądry i szybko ;-)

1
>>> l = [0,1,1,2,2] 
>>> [x for x in l if l.count(x) == 1] 
[0] 
Powiązane problemy