Ich habe eine Liste von Python-Objekten, die ich nach einem bestimmten Attribut jedes Objekts sortieren möchte:
[Tag(name="toe", count=10), Tag(name="leg", count=2), ...]
Wie sortiere ich die Liste nach .count
absteigend?
Ich habe eine Liste von Python-Objekten, die ich nach einem bestimmten Attribut jedes Objekts sortieren möchte:
[Tag(name="toe", count=10), Tag(name="leg", count=2), ...]
Wie sortiere ich die Liste nach .count
absteigend?
Um die Liste an Ort und Stelle zu sortieren:
orig_list.sort(key=lambda x: x.count, reverse=True)
Um eine neue Liste zurückzugeben, verwenden Sie sorted
:
new_list = sorted(orig_list, key=lambda x: x.count, reverse=True)
Erklärung:
key=lambda x: x.count
sortiert nach Anzahl.reverse=True
sortiert in absteigender Reihenfolge.Mehr zu Sortieren nach Schlüsseln.
Kein Problem. Übrigens, wenn Muhuk recht hat und es sich um eine Liste von Django-Objekten handelt, solltest du seine Lösung in Betracht ziehen. Für den allgemeinen Fall des Sortierens von Objekten ist meine Lösung wahrscheinlich bewährte Praxis.
Bei großen Listen erzielen Sie eine bessere Leistung, wenn Sie operator.attrgetter('count') als Ihren Schlüssel verwenden. Dies ist nur eine optimierte (niedrigere Ebene) Form der Lambda-Funktion in dieser Antwort.
Vielen Dank für die großartige Antwort. Falls es sich um eine Liste von Wörterbüchern handelt und "count" einer ihrer Schlüssel ist, muss es wie folgt geändert werden: ut.sort(key=lambda x: x['count'], reverse=True)
Eine Möglichkeit, die am schnellsten sein kann, insbesondere wenn Ihre Liste viele Einträge enthält, besteht darin, operator.attrgetter("count")
zu verwenden. Dies könnte jedoch auf einer Vor-Operator-Version von Python ausgeführt werden, daher wäre es gut, einen Ausfallmechanismus zu haben. Dann könnten Sie Folgendes tun:
try: import operator
except ImportError: keyfun= lambda x: x.count # Verwenden Sie ein Lambda, wenn kein Operator-Modul vorhanden ist
else: keyfun= operator.attrgetter("count") # Verwenden Sie den Operator, da er schneller als Lambda ist
ut.sort(key=keyfun, reverse=True) # sortieren Sie direkt vor Ort
Hier würde ich den Variablennamen "keyfun" anstelle von "cmpfun" verwenden, um Verwirrung zu vermeiden. Die sort() Methode akzeptiert auch eine Vergleichsfunktion über das Argument cmp=.
Dies scheint nicht zu funktionieren, wenn dem Objekt dynamisch hinzugefügte Attribute vorliegen (wenn Sie self.__dict__ = {'some':'dict'}
nach der __init__
-Methode durchgeführt haben). Ich weiß nicht, warum es anders sein sollte, allerdings.
@tutuca: Ich habe die Instanz __dict__
noch nie ersetzt. Beachten Sie, dass die Konzepte "ein Objekt mit dynamisch hinzugefügten Attributen haben" und "das __dict__
-Attribut eines Objekts setzen" fast orthogonal sind. Ich sage das, weil Ihr Kommentar zu implizieren scheint, dass das Setzen des __dict__
-Attributs eine Voraussetzung für das dynamische Hinzufügen von Attributen ist.
Leser sollten beachten, dass die Methode key=:
ut.sort(key=lambda x: x.count, reverse=True)
viele Male schneller ist als das Hinzufügen von Rich-Vergleichsoperatoren zu den Objekten. Ich war überrascht dies zu lesen (Seite 485 von "Python in a Nutshell"). Sie können dies bestätigen, indem Sie Tests mit diesem kleinen Programm durchführen:
#!/usr/bin/env python
import random
class C:
def __init__(self,count):
self.count = count
def __cmp__(self,other):
return cmp(self.count,other.count)
longList = [C(random.random()) for i in xrange(1000000)] # etwa 6,1 Sekunden
longList2 = longList[:]
longList.sort() # etwa 52 - 6.1 = 46 Sekunden
longList2.sort(key = lambda c: c.count) # etwa 9 - 6.1 = 3 Sekunden
Meine sehr minimalen Tests zeigen, dass die erste Sortierung mehr als 10 Mal langsamer ist, aber das Buch sagt, dass sie im Allgemeinen nur etwa 5 Mal langsamer ist. Der Grund, den sie angeben, ist der hoch optimierte Sortieralgorithmus, der in Python verwendet wird (timsort).
Dennoch ist es sehr seltsam, dass .sort(lambda) schneller ist als das gewöhnliche .sort(). Ich hoffe, sie beheben das.
Die Definition von __cmp__
entspricht einem Aufruf von .sort(cmp=lambda)
, nicht .sort(key=lambda)
, daher ist es überhaupt nicht merkwürdig.
@tzot hat genau recht. Der erste Sortiervorgang muss Objekte immer wieder miteinander vergleichen. Der zweite Sortiervorgang greift jedes Objekt nur einmal ab, um seinen Zählwert zu extrahieren, und führt dann eine einfache numerische Sortierung durch, die sehr optimiert ist. Ein fairerer Vergleich wäre longList2.sort(cmp = cmp)
. Ich habe das ausprobiert und es hat fast genauso gut funktioniert wie .sort()
. (Anmerkung: Beachten Sie auch, dass der "cmp" Sortierparameter in Python 3 entfernt wurde.)
Objektorientierter Ansatz
Es ist eine gute Praxis, die Objektsortierlogik, falls zutreffend, als Eigenschaft der Klasse zu erstellen, anstatt sie in jede Instanz einzubauen, in der die Sortierung erforderlich ist.
Dies stellt Konsistenz sicher und beseitigt die Notwendigkeit für Boilerplate-Code.
Mindestens sollten Sie __eq__
und __lt__
Operationen angeben, damit dies funktioniert. Dann verwenden Sie einfach sorted(list_of_objects)
.
class Card(object):
def __init__(self, rank, suit):
self.rank = rank
self.suit = suit
def __eq__(self, other):
return self.rank == other.rank and self.suit == other.suit
def __lt__(self, other):
return self.rank < other.rank
hand = [Card(10, 'H'), Card(2, 'h'), Card(12, 'h'), Card(13, 'h'), Card(14, 'h')]
hand_order = [c.rank for c in hand] # [10, 2, 12, 13, 14]
hand_sorted = sorted(hand)
hand_sorted_order = [c.rank for c in hand_sorted] # [2, 10, 12, 13, 14]
Das ist genau das, wonach ich gesucht habe! Könnten Sie uns auf einige Dokumentationen verweisen, die erklären, warum __eq__
und __lt__
die Mindestimplementierungsanforderungen sind?
@FriendFX, ich glaube, dass es durch dieses impliziert wird: • Die Sortierroutinen verwenden garantiert __lt__() beim Vergleichen von zwei Objekten...
@FriendFX: Siehe portingguide.readthedocs.io/en/latest/comparisons.html für Vergleiche und Sortieren
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.
2 Stimmen
Dupe: stackoverflow.com/questions/157424/…, stackoverflow.com/questions/222752/…, stackoverflow.com/questions/327191/…
7 Stimmen
Sortieranleitung für diejenigen, die mehr Informationen über das Sortieren in Python suchen.
1 Stimmen
Abgesehen von operator.attrgetter ('attribut_name') können Sie auch Funktoren als Schlüssel verwenden, wie z.B. object_list.sort(key=my_sorting_functor ('my_key')), wobei die Implementierung absichtlich ausgelassen wird.