Comment trier une liste d'objets en fonction d'un attribut des objets?

j'ai une liste d'objets Python que j'aimerais par un attribut des objets eux-mêmes. La liste ressemble à:

>>> ut
[<Tag: 128>, <Tag: 2008>, <Tag: <>, <Tag: actionscript>, <Tag: addresses>,
 <Tag: aes>, <Tag: ajax> ...]

chaque objet a un nombre:

>>> ut[1].count
1L

je dois trier la liste par nombre de nombres décroissants.

j'ai vu plusieurs méthodes pour cela, mais je suis à la recherche de la meilleure pratique en Python.

557
demandé sur jpp 2008-12-31 19:41:32

7 réponses

# 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)

plus sur Tri par touches "

952
répondu Triptych 2009-01-09 18:07:57

une façon qui peut être la plus rapide, surtout si votre liste a beaucoup de dossiers, est d'utiliser operator.attrgetter("count") . Cependant, cela pourrait fonctionner sur une version pré-opérateur de Python, donc il serait bien d'avoir un mécanisme de repli. Vous pourriez vouloir faire ce qui suit, alors:

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
60
répondu tzot 2018-02-28 10:01:31

les lecteurs devraient noter que la clé = méthode:

ut.sort(key=lambda x: x.count, reverse=True)

est beaucoup plus rapide que l'ajout d'opérateurs de comparaison riches aux objets. J'ai été surpris de lire ceci (page 485 de "Python en un Mot"). Vous pouvez le confirmer en exécutant des tests sur ce petit programme:

#!/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

mes tests, très minimes, montrent que la première sorte est plus de 10 fois plus lente, mais le livre dit qu'elle est seulement environ 5 fois plus lente en général. La raison pour laquelle ils say est due à l'algorithme de tri hautement optimisé utilisé en python ( timsort ).

toujours, c'est très étrange .de tri(lambda) est plus rapide que d'ordinaire .sorte.)( J'espère qu'ils vont corriger ça.

52
répondu Jose M Vidal 2012-11-15 14:17:06
from operator import attrgetter
ut.sort(key = attrgetter('count'), reverse = True)
28
répondu 2008-12-31 19:00:33

cela ressemble beaucoup à une liste D'instances modèles de Django ORM.

pourquoi ne pas les trier sur requête comme ceci:

ut = Tag.objects.order_by('-count')
13
répondu muhuk 2008-12-31 17:10:00

approche orientée objet

c'est une bonne pratique de faire de la logique de tri d'objet, s'il y a lieu, une propriété de la classe plutôt qu'incorporée dans chaque cas où l'ordre est requis.

cela garantit la cohérence et élimine le besoin de code sur la bobine.

au minimum, vous devez spécifier les opérations __eq__ et __lt__ pour que cela fonctionne. Alors utilisez 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]
12
répondu jpp 2018-02-11 11:35:22

ajoute rich comparison operators à la classe objet, puis utilise la méthode sort() de la liste.

Voir comparaisons riches en python .


mise à jour : bien que cette méthode fonctionnerait, je pense que la solution de Triptych est mieux adapté à votre cas parce que beaucoup plus simple.

9
répondu Roberto Liffredo 2008-12-31 16:45:15