Pregunta

Tengo una lista de objetos de Python que me gustaría ordenar por un atributo de los mismos objetos. La lista parece:

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

Cada objeto tiene un conteo:

>>> ut[1].count
1L

Necesito ordenar la lista por número de conteos descendente.

He visto varios métodos para esto, pero estoy buscando las mejores prácticas en Python.

¿Fue útil?

Solución

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

Más sobre ordenar por claves »

Otros consejos

Una forma que puede ser más rápida, especialmente si su lista tiene muchos registros, es usar operator.attrgetter (" count ") . Sin embargo, esto podría ejecutarse en una versión pre-operativa de Python, por lo que sería bueno tener un mecanismo de respaldo. Es posible que desee hacer lo siguiente, entonces:

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

Los lectores deben notar que la clave = método:

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

es muchas veces más rápido que agregar operadores de comparación ricos a los objetos. Me sorprendió leer esto (página 485 de "Python en una cáscara de nuez"). Puedes confirmar esto ejecutando pruebas en este pequeño programa:

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

Mis pruebas, muy mínimas, muestran que el primer tipo es 10 veces más lento, pero el libro dice que solo es 5 veces más lento en general. La razón por la que dicen se debe al algoritmo de ordenamiento altamente optimizado utilizado en Python ( timsort ).

Aún así, es muy extraño que .sort (lambda) sea más rápido que el antiguo .sort (). Espero que lo solucionen.

from operator import attrgetter
ut.sort(key = attrgetter('count'), reverse = True)

Enfoque orientado a objetos

Es una buena práctica hacer que la lógica de ordenación de objetos, si corresponde, una propiedad de la clase en lugar de incorporarse en cada instancia, se requiere el ordenamiento.

Esto asegura la consistencia y elimina la necesidad de código de repetición.

Como mínimo, debe especificar las operaciones __eq__ y __lt__ para que esto funcione. Luego solo use ordenado (lista_de_objetos) .

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]

Se parece mucho a una lista de instancias del modelo ORM de Django.

¿Por qué no ordenarlos en una consulta como esta:

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

Agregue operadores de comparación ricos a la clase de objeto, luego use el método sort () de la lista.
Consulte comparación rica en python .


Actualización : aunque este método funcionaría, creo que la solución de Triptych se adapta mejor a su caso porque es mucho más simple.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top