Benutzerdefinierte Vergleich Funktionen zum Sortieren, wie in bestehenden Antworten vorgeschlagen, machen es einfach, in einer Mischung von aufsteigend zu sortieren und absteigende Aufträge - aber sie haben schwerwiegende Leistungsprobleme und wurden in Python 3 entfernt, so dass nur die bevorzugte Anpassung Ansatz - benutzerdefinierte Tasten-Extraktion Funktionen ... viel schneller, obwohl zarter für den relativ seltenen Anwendungsfall zu verwenden von gemischt aufsteigende/absteigende Sortierungen.
In Python 2.*
, die entweder Art der Anpassung unterstützt (nicht beide im selben Aufruf zu sort
oder sorted
:-), eine benutzerdefinierten Vergleichsfunktion kann als cmp=
benannte Argument übergeben werden; oder eine benutzerdefinierte Schlüsselextraktionsfunktion kann als key=
genanntes Argument übergeben werden. In Python 3.*
ist nur die letztere Option verfügbar.
Es ist definitiv wert, den Schlüsselextraktionsansatz zu verstehen, auch wenn Sie glauben, dass Sie Ihr Problem gerade mit einem benutzerdefinierten Vergleichsansatz gelöst haben: nicht nur für die Leistung, sondern auch für die Zukunftssicherheit (Python 3) und für die Allgemeinheit (Der key=
Ansatz gilt auch für min
, max
, itertools.groupby
... viel allgemeiner als der cmp=
Ansatz!).
Die Schlüsselextraktion ist sehr einfach, wenn alle Schlüsselunterfelder auf die gleiche Weise sortiert werden sollen (alle aufsteigend oder alle absteigend) - Sie extrahieren sie einfach; es ist immer noch ziemlich einfach, wenn die Teilfelder, die "andersherum" gehen, Zahlen sind (man ändert nur ihr Vorzeichen während des Extrahierens); Der heikle Fall ist genau der Fall, den Sie haben - mehrere String-Felder, die auf unterschiedliche Weise verglichen werden müssen.
Ein relativ einfacher Ansatz, Ihr Problem zu lösen, ist eine winzige Shim Klasse:
class Reverser(object):
def __init__(self, s): self.s = s
def __lt__(self, other): return other.s < self.s
def __eq__(self, other): return other.s == self.s
Beachten Sie, dass Sie nur __lt__
und __eq__
(die <
und ==
Betreiber) zu versorgen haben - sort
und Freunde synthetisieren all andere Vergleiche, falls erforderlich, basierend auf diesen beiden.
Also, mit diesem kleinen Hilfsmittel bewaffnet, wir leicht gehen können ...:
def getkey(tup):
a, b = tup[0].split('_')
return Reverser(a), b
my_list.sort(key=getkey)
Wie Sie sehen, wenn Sie „get“ die Umkehrer und Schlüssel Absaugkonzepte, zahlen Sie im Wesentlichen kein Preis für Verwenden von Schlüssel - Extraktion anstelle von benutzerdefinierten Vergleich: der Code, den ich vorschlage, ist 4 Anweisungen für die Umkehrer - Klasse (die Sie einmal schreiben können und irgendwo in Ihrem "Goodies Bag" Modul), drei für die Schlüsselextraktion Funktion, und natürlich eine für die sort
oder sorted
Aufruf - insgesamt acht vs die 4 + 1 == 5 des benutzerdefinierten Vergleichs Ansatz in der kompaktesten Form (dh die entweder cmp mit einem Vorzeichenwechsel oder cmp mit vertauschten argume nts). Drei Aussagen sind nicht viel von einem Preis für die Vorteile der Schlüsselextraktion! -)
Leistung ist eindeutig kein großes Problem mit solch einer kurzen Liste, aber mit einem sogar bescheidenen (10 mal) eins ...:
# my_list as in the Q, my_cmp as per top A, getkey as here
def bycmp():
return sorted(my_list*10, cmp=my_cmp)
def bykey():
return sorted(my_list*10, key=getkey)
...
$ python -mtimeit -s'import so' 'so.bykey()'
1000 loops, best of 3: 548 usec per loop
$ python -mtimeit -s'import so' 'so.bycmp()'
1000 loops, best of 3: 995 usec per loop
Ie, der key=
Ansatz bereits eine Leistungssteigerung von fast zwei mal zeigt (die Liste doppelt so schnell Sortierung), wenn sie auf einer 50-Elemente-Liste arbeiten - auch den bescheidenen Preis von „8 Zeilen wert eher als 5 ", besonders mit all den anderen Vorteilen, die ich bereits erwähnt habe!
Wow, ich mag deine Lösung. Ich wusste nicht, dass der cmp = Ansatz eine solche Strafe hatte. –
@Steven, tx - yep, nicht jeder versteht, warum cmp = in Python 3 entfernt wurde (als "attraktives Ärgernis", das Leute dazu verleitet, eine Leistungseinbuße zu erleiden!), Genau deshalb habe ich diese detaillierte Erklärung gepostet, danke zur Bestätigung kann es helfen! -) –
@Alex: Ich zögere, eine * Antwort * zu bearbeiten, aber vielleicht sollte my_list.key (cmp = my_cmp) my_list.sort (key = getkey) sein? –