Wie eine Liste von Objekten sortieren basierend auf einem Attribut der Objekte?
Frage
Ich habe eine Liste von Python-Objekte, die ich selbst durch ein Attribut der Objekte sortieren möchten. Die Liste wie folgt aussieht:
>>> ut
[<Tag: 128>, <Tag: 2008>, <Tag: <>, <Tag: actionscript>, <Tag: addresses>,
<Tag: aes>, <Tag: ajax> ...]
Jedes Objekt hat eine Zählung:
>>> ut[1].count
1L
Ich brauche absteigend die Liste nach Anzahl der Zählungen zu sortieren.
Ich habe für diese verschiedenen Methoden gesehen, aber ich bin für die beste Praxis in Python suchen.
Lösung
# To sort the list in place...
ut.sort(key=lambda x: x.count, reverse=True)
# To return a new list, use the sorted() built-in function...
newlist = sorted(ut, key=lambda x: x.count, reverse=True)
Andere Tipps
Eine Art und Weise, die am schnellsten sein kann, vor allem, wenn Ihre Liste viele Datensätze hat, ist operator.attrgetter("count")
zu verwenden. Allerdings könnte dies auf einer Pre-Operator Version von Python laufen, also es wäre schön, einen Fallback-Mechanismus zu haben. Vielleicht möchten Sie folgendes tun, dann:
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
Die Leser sollten beachten, dass der Schlüssel = Methode:
ut.sort(key=lambda x: x.count, reverse=True)
ist ein Vielfaches schneller als das Hinzufügen reichen Vergleichsoperatoren zu den Objekten. Ich war überrascht, diese (Seite 485 von „Python in a Nutshell“) zu lesen. Sie können dies bestätigen durch Tests auf diesem kleinen Programm ausgeführt wird:
#!/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
My, sehr minimal, zeigen Tests die erste Art mehr als 10-mal langsamer, aber das Buch sagt, dass es nur etwa 5-mal langsamer im Allgemeinen. Der Grund, warum sie sagen, ist aufgrund der Optimierung sehr Sortieralgorithmus in Python verwendet ( Timsort ).
Still, es ist sehr seltsam, dass .Sort (Lambda) ist schneller als normale alte .Sort (). Ich hoffe, dass sie das in Ordnung bringen.
from operator import attrgetter
ut.sort(key = attrgetter('count'), reverse = True)
Die objektorientierte Ansatz
Es ist eine gute Übung, um Objektsortierlogik zu machen ggf. eine Eigenschaft der Klasse und nicht der Bestellung erforderlich ist, in jedem Fall aufgenommen wird.
Dies gewährleistet die Konsistenz und beseitigt die Notwendigkeit für Standardcode.
Als Minimum sollten Sie __eq__
und __lt__
Operationen angeben, für diese zu arbeiten. Dann einfach sorted(list_of_objects)
verwenden.
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]
Es sieht aus wie eine Liste von Django ORM Modellinstanzen.
Warum sie nicht auf Abfrage sortiert werden wie folgt aus:
ut = Tag.objects.order_by('-count')
Fügen Sie reichen Vergleichsoperatoren auf die Objektklasse, dann verwenden Sie sort () -Methode der Liste.
Siehe rel="noreferrer">.
Aktualisieren : Obwohl diese Methode funktionieren würde, denke ich Lösung von Triptychon besser zu Ihrem Fall geeignet ist, da Art und Weise einfacher
.