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
in absteigender Reihenfolge?
Nick Sergeant
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
in absteigender Reihenfolge?
Kenan-Banken
So sortieren Sie die Liste an Ort und Stelle:
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)
Erläuterung:
key=lambda x: x.count
sortiert nach Anzahl.reverse=True
sortiert in absteigender Reihenfolge.Mehr dazu Sortierung nach Schlüsseln.
Kein Problem. Übrigens, wenn muhuk Recht hat und es sich um eine Liste von Django-Objekten handelt, sollten Sie seine Lösung in Betracht ziehen. Für den allgemeinen Fall des Sortierens von Objekten ist meine Lösung jedoch wahrscheinlich die beste Vorgehensweise.
– Kenan-Banken
31. Dezember 2008 um 17:12 Uhr
Bei großen Listen erhalten Sie eine bessere Leistung, wenn Sie operator.attrgetter(‘count’) als Schlüssel verwenden. Dies ist nur eine optimierte (untere) Form der Lambda-Funktion in dieser Antwort.
– David Eik
31. Dezember 2008 um 19:35 Uhr
Danke für die tolle Antwort. Falls es sich um eine Liste von Wörterbüchern handelt und „count“ einer ihrer Schlüssel ist, muss sie wie folgt geändert werden: ut.sort(key=lambda x: x[‘count’]umgekehrt = wahr)
– dganesh2002
8. Dezember 2016 um 21:20 Uhr
Ich nehme an, es verdient das folgende Update: Wenn nach mehreren Feldern sortiert werden muss, kann dies durch aufeinanderfolgende Aufrufe von sort() erreicht werden, da Python einen stabilen Sortieralgorithmus verwendet.
– uuu777
23. Februar 2020 um 14:41 Uhr
Danke @KenanBanks, du hattest recht. Ärgerlicherweise machte Outlook einige seltsame Dinge mit Kalenderzeitzonen, so dass einige ohne die Zeitzonendetails durchkamen … keine Ahnung warum!
– Schmied
20. April 2022 um 6:05 Uhr
tzot
Eine Möglichkeit, die am schnellsten sein kann, insbesondere wenn Ihre Liste viele Datensätze enthält, ist die Verwendung operator.attrgetter("count")
. Dies könnte jedoch auf einer Pre-Operator-Version von Python ausgeführt werden, daher wäre es schön, einen Fallback-Mechanismus zu haben. Vielleicht möchten Sie dann Folgendes tun:
try: import operator
except ImportError: keyfun= lambda x: x.count # use a lambda if no operator module
else: keyfun= operator.attrgetter("count") # use operator since it's faster than lambda
ut.sort(key=keyfun, reverse=True) # sort in-place
Hier würde ich den Variablennamen „keyfun“ anstelle von „cmpfun“ verwenden, um Verwirrung zu vermeiden. Die Methode sort() akzeptiert auch eine Vergleichsfunktion über das Argument cmp=.
– akaihola
2. Januar 2009 um 12:16 Uhr
Dies scheint nicht zu funktionieren, wenn das Objekt dynamisch hinzugefügte Attribute hat (falls Sie dies getan haben self.__dict__ = {'some':'dict'}
nach dem __init__
Methode). Ich wüsste aber nicht, warum es anders sein sollte.
– tutuca
7. Januar 2013 um 20:40 Uhr
@tutuca: Ich habe die Instanz nie ersetzt __dict__
. Beachten Sie, dass „ein Objekt mit dynamisch hinzugefügten Attributen“ und „ein Objekt festlegen __dict__
Attribut” sind fast orthogonale Konzepte. Ich sage das, weil Ihr Kommentar zu implizieren scheint, dass die Einstellung der __dict__
Das Attribut ist eine Voraussetzung für das dynamische Hinzufügen von Attributen.
– zot
9. Januar 2013 um 23:14 Uhr
@tzot: Wenn ich die Verwendung von verstehe operator.attrgetter
könnte ich eine Funktion mit einem beliebigen Eigenschaftsnamen bereitstellen und eine sortierte Sammlung zurückgeben.
– IAbstract
24. Februar 2016 um 18:16 Uhr
Für diejenigen, die weitere Informationen suchen: wiki.python.org/moin/HowTo/Sorting#Operator_Module_Functions
– alekosot
20. Januar 2017 um 15:01 Uhr
José M. Vidal
Leser sollten beachten, dass die Methode key=:
ut.sort(key=lambda x: x.count, reverse=True)
ist um ein Vielfaches schneller als das Hinzufügen umfangreicher 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 ausfü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)] #about 6.1 secs
longList2 = longList[:]
longList.sort() #about 52 - 6.1 = 46 secs
longList2.sort(key = lambda c: c.count) #about 9 - 6.1 = 3 secs
Meine sehr minimalen Tests zeigen, dass die erste Sorte mehr als 10-mal langsamer ist, aber das Buch sagt, dass sie im Allgemeinen nur etwa 5-mal langsamer ist. Der Grund, den sie sagen, ist auf den hochoptimierten Sortieralgorithmus zurückzuführen, der in Python verwendet wird (Zeitsort).
Trotzdem ist es sehr seltsam, dass .sort(lambda) schneller ist als das einfache alte .sort(). Ich hoffe, sie beheben das.
Definieren __cmp__
ist gleichbedeutend mit anrufen .sort(cmp=lambda)
nicht .sort(key=lambda)
also ist es überhaupt nicht seltsam.
– zot
9. September 2019 um 7:46 Uhr
@tzot ist genau richtig. Die erste Sorte muss immer wieder Gegenstände miteinander vergleichen. Die zweite Sortierung greift nur einmal auf jedes Objekt zu, um seinen Zählwert zu extrahieren, und führt dann eine einfache numerische Sortierung durch, die hochoptimiert ist. Ein fairer Vergleich wäre longList2.sort(cmp = cmp)
. Ich habe das ausprobiert und es hat fast die gleiche Leistung erbracht wie .sort()
. (Außerdem: Beachten Sie, dass der Sortierparameter „cmp“ in Python 3 entfernt wurde.)
– Bryan Roach
29. Oktober 2019 um 4:56 Uhr
Objektorientierter Ansatz
Es empfiehlt sich, die Objektsortierlogik, falls zutreffend, zu einer Eigenschaft der Klasse zu machen, anstatt sie in jeder Instanz zu integrieren, in der die Reihenfolge erforderlich ist.
Dies gewährleistet Konsistenz und macht Boilerplate-Code überflüssig.
Sie sollten mindestens angeben __eq__
Und __lt__
Operationen, damit dies funktioniert. Dann einfach verwenden 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]
from operator import attrgetter
ut.sort(key = attrgetter('count'), reverse = True)
Muhuk
Es sieht aus wie eine Liste von Django-ORM-Modellinstanzen.
Warum sortieren Sie sie nicht nach Abfrage wie folgt:
ut = Tag.objects.order_by('-count')
rauben
Fügen Sie der Objektklasse umfangreiche Vergleichsoperatoren hinzu und verwenden Sie dann die Methode sort() der Liste.
Sehen reichhaltiger Vergleich in Python.
Aktualisieren: Obwohl diese Methode funktionieren würde, denke ich, dass die Lösung von Triptych für Ihren Fall besser geeignet ist, weil sie viel einfacher ist.
Dupe: stackoverflow.com/questions/157424/…, stackoverflow.com/questions/222752/…, stackoverflow.com/questions/327191/…
– S. Lott
31. Dezember 2008 um 18:23 Uhr
Sortieren, wie für diejenigen, die nach weiteren Informationen zum Sortieren in Python suchen.
– Jeyekomon
30. Mai 2018 um 8:48 Uhr
abgesehen von operator.attrgetter(‘attribute_name’) können Sie auch Funktoren als Schlüssel wie object_list.sort(key=my_sorting_functor(‘my_key’) verwenden und die Implementierung bewusst weglassen.
– Vijay Shanker
8. April 2019 um 20:07 Uhr