it-swarm.com.de

Wie sortiere ich eine Liste von Objekten basierend auf einem Attribut der Objekte?

Ich habe eine Liste von Python Objekten, die ich nach einem Attribut der Objekte selbst sortieren möchte. Die Liste sieht folgendermaßen aus:

>>> 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 muss die Liste nach Anzahl der absteigenden Zählungen sortieren.

Ich habe verschiedene Methoden dafür gesehen, aber ich suche nach bewährten Methoden in Python.

685
Nick Sergeant
# 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)

Mehr zu Sortierung nach Schlüsseln "

1133
Triptych

Eine Möglichkeit, die am schnellsten ist, insbesondere wenn Ihre Liste viele Datensätze enthält, ist die Verwendung von operator.attrgetter("count"). Dies könnte jedoch auf einer Vor-Operator-Version von Python ausgeführt werden, sodass ein Fallback-Mechanismus wünschenswert wäre. 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
75
tzot

Leser sollten beachten, dass die key = -Methode:

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 zehnmal langsamer ist, aber das Buch sagt, dass sie im Allgemeinen nur fünfmal langsamer ist. Der Grund, den sie sagen, ist der hoch optimierte Sortieralgorithmus, der in python (timsort) verwendet wird.

Trotzdem ist es sehr merkwürdig, dass .sort (Lambda) schneller ist als einfaches altes .sort (). Ich hoffe, dass sie das beheben.

59
Jose M Vidal
from operator import attrgetter
ut.sort(key = attrgetter('count'), reverse = True)
34
attrgetter

Objektorientierter Ansatz

Gegebenenfalls empfiehlt es sich, die Objekt-Sortierlogik zu einer Eigenschaft der Klasse zu machen, anstatt die Reihenfolge in jeder Instanz zu berücksichtigen.

Dies stellt die Konsistenz sicher und beseitigt die Notwendigkeit von Boilerplate-Code.

Sie sollten mindestens die Vorgänge __eq__ und __lt__ angeben, damit dies funktioniert. Dann benutzen 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]
31
jpp

Es sieht ungefähr so ​​aus wie eine Liste von Django ORM-Modellinstanzen.

Warum sortieren Sie sie nicht auf Anfrage wie folgt:

ut = Tag.objects.order_by('-count')
15
muhuk

Fügen Sie der Objektklasse Rich-Vergleichsoperatoren hinzu, und verwenden Sie dann die sort () -Methode der Liste.
Siehe reicher Vergleich in Python .


Update : Obwohl diese Methode funktionieren würde, denke ich, dass die Lösung von Triptychon besser für Ihren Fall geeignet ist, da sie viel einfacher ist.

10
rob