>>> k = [[1, 2], [4], [5, 6, 2], [1, 2], [3], [4]]
>>> import itertools
>>> k.sort()
>>> list(k for k,_ in itertools.groupby(k))
[[1, 2], [3], [4], [5, 6, 2]]
itertoolsoft bietet die schnellsten und leistungsstärksten Lösungen für diese Art von Problemen, und ist gut lohnt sich , mit bestens vertraut! -)
Bearbeiten : Wie ich in einem Kommentar erwähne, konzentrieren sich normale Optimierungsbemühungen auf große Eingaben (der Big-O-Ansatz), da dies so viel einfacher ist, dass es eine gute Rendite bietet. Aber manchmal (im Wesentlichen für "tragisch entscheidende Engpässe" in tiefen inneren Codeschleifen, die die Grenzen von Leistungsgrenzen überschreiten) muss man möglicherweise viel detaillierter vorgehen, Wahrscheinlichkeitsverteilungen bereitstellen und entscheiden, welche Leistungsmaße optimiert werden sollen (möglicherweise die Obergrenze oder Das 90. Zentil ist wichtiger als ein Durchschnitt oder Median, abhängig von den eigenen Apps. Es führt zu Beginn möglicherweise heuristische Überprüfungen durch, um je nach den Eigenschaften der Eingabedaten unterschiedliche Algorithmen auszuwählen.
Sorgfältige Messungen der "Punkt" -Leistung (Code A gegenüber Code B für eine bestimmte Eingabe) sind Teil dieses äußerst kostspieligen Prozesses, und das Standardbibliotheksmodul timeithilft hier. Es ist jedoch einfacher, es an einer Shell-Eingabeaufforderung zu verwenden. Im Folgenden finden Sie ein kurzes Modul, in dem der allgemeine Ansatz für dieses Problem vorgestellt wird. Speichern Sie es wie folgt nodup.py:
import itertools
k = [[1, 2], [4], [5, 6, 2], [1, 2], [3], [4]]
def doset(k, map=map, list=list, set=set, tuple=tuple):
return map(list, set(map(tuple, k)))
def dosort(k, sorted=sorted, xrange=xrange, len=len):
ks = sorted(k)
return [ks[i] for i in xrange(len(ks)) if i == 0 or ks[i] != ks[i-1]]
def dogroupby(k, sorted=sorted, groupby=itertools.groupby, list=list):
ks = sorted(k)
return [i for i, _ in itertools.groupby(ks)]
def donewk(k):
newk = []
for i in k:
if i not in newk:
newk.append(i)
return newk
# sanity check that all functions compute the same result and don't alter k
if __name__ == '__main__':
savek = list(k)
for f in doset, dosort, dogroupby, donewk:
resk = f(k)
assert k == savek
print '%10s %s' % (f.__name__, sorted(resk))
Beachten Sie die Überprüfung der geistigen Gesundheit (wird durchgeführt, wenn Sie dies gerade tun python nodup.py) und die grundlegende Hebetechnik (machen Sie konstante globale Namen für jede Funktion lokal, um die Geschwindigkeit zu erhöhen), um die Dinge gleichberechtigt zu machen.
Jetzt können wir die winzige Beispielliste überprüfen:
$ python -mtimeit -s'import nodup' 'nodup.doset(nodup.k)'
100000 loops, best of 3: 11.7 usec per loop
$ python -mtimeit -s'import nodup' 'nodup.dosort(nodup.k)'
100000 loops, best of 3: 9.68 usec per loop
$ python -mtimeit -s'import nodup' 'nodup.dogroupby(nodup.k)'
100000 loops, best of 3: 8.74 usec per loop
$ python -mtimeit -s'import nodup' 'nodup.donewk(nodup.k)'
100000 loops, best of 3: 4.44 usec per loop
Bestätigung, dass der quadratische Ansatz klein genug ist, um für kleine Listen mit wenigen doppelten Werten attraktiv zu sein. Mit einer kurzen Liste ohne Duplikate:
$ python -mtimeit -s'import nodup' 'nodup.donewk([[i] for i in range(12)])'
10000 loops, best of 3: 25.4 usec per loop
$ python -mtimeit -s'import nodup' 'nodup.dogroupby([[i] for i in range(12)])'
10000 loops, best of 3: 23.7 usec per loop
$ python -mtimeit -s'import nodup' 'nodup.doset([[i] for i in range(12)])'
10000 loops, best of 3: 31.3 usec per loop
$ python -mtimeit -s'import nodup' 'nodup.dosort([[i] for i in range(12)])'
10000 loops, best of 3: 25 usec per loop
Der quadratische Ansatz ist nicht schlecht, aber die Sortierung und die Gruppierung sind besser. Usw. usw.
Wenn sich diese Operation (wie die Besessenheit von der Leistung nahelegt) in einer inneren Kernschleife Ihrer Anwendung zum Überschreiten der Grenzen befindet, lohnt es sich, die gleichen Tests an anderen repräsentativen Eingabebeispielen durchzuführen, um möglicherweise eine einfache Maßnahme zu ermitteln, die Sie heuristisch zulassen könnte Wählen Sie den einen oder anderen Ansatz (aber die Maßnahme muss natürlich schnell sein).
Es lohnt sich auch, eine andere Darstellung beizubehalten k- warum muss es sich überhaupt um eine Liste von Listen und nicht um eine Reihe von Tupeln handeln? Wenn die Aufgabe zum Entfernen von Duplikaten häufig ist und die Profilerstellung zeigt, dass es sich um den Leistungsengpass des Programms handelt, kann es beispielsweise insgesamt schneller sein, ständig eine Reihe von Tupeln beizubehalten und nur dann eine Liste von Listen abzurufen, wenn und wo dies erforderlich ist.