ja jak filtrowanie tej listyPythona filtrowania listy tylko pozostawiają obiekty występujące po
l = [0,1,1,2,2]
tylko wyjść,
[0].
Staram się robić to w sposób "pytonowy": o) Czy jest to możliwe bez zagnieżdżonych pętli?
ja jak filtrowanie tej listyPythona filtrowania listy tylko pozostawiają obiekty występujące po
l = [0,1,1,2,2]
tylko wyjść,
[0].
Staram się robić to w sposób "pytonowy": o) Czy jest to możliwe bez zagnieżdżonych pętli?
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]]
+1 Naprawdę ładne, gromadzi niewiele więcej informacji, niż potrzebujesz, aby rozwiązać zadanie. Możesz jednak pozbyć się '.keys()'. –
Tak, .keys() jest całkowicie opcjonalnym, ale nieco bardziej czytelnym IMO. – mhawke
ł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. –
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 są 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ć ;-) .
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?) –
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
Drugie rozwiązanie nie wydaje się właściwe: usuwa duplikaty, ale problem polegał na usunięciu wszystkich duplikatów. –
[x for x in the_list if the_list.count(x)==1]
Chociaż nadal jest to pętla zagnieżdżona za kulisami.
Tak, O (N ** 2) (podczas gdy podejście nie-zagnieżdżone, które pokazuję, to O (N)). –
Wydaje mi się, że wolę rozwiązanie Alexa, ponieważ sprawdza ono tylko listę dwukrotnie, twoje rozwiązanie to n^2. –
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. –
>>> l = [0,1,1,2,2]
>>> [x for x in l if l.count(x) is 1]
[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
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 *. –
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. –
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)
Konwertowanie z powrotem do listy byłoby miłe. – nilamo
To nie zachowuje porządku, jak robi to Alex. –
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]
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 ;-)
>>> l = [0,1,1,2,2]
>>> [x for x in l if l.count(x) == 1]
[0]
@Scott - Przeczytaj ten tytuł. – Markus
@Markus - Tak, to pomaga! Myślę, że muszę być ślepy. Zamierzam usunąć mój oryginalny komentarz, zanim wszyscy pomyślą, że jestem idiotą! :) –