Domanda

Ho un elenco di oggetti Python che vorrei ordinare per un attributo degli oggetti stessi. L'elenco è simile a:

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

Ogni oggetto ha un conteggio:

>>> ut[1].count
1L

Devo ordinare l'elenco in base al numero di conteggi decrescenti.

Ho visto diversi metodi per questo, ma sto cercando le migliori pratiche in Python.

È stato utile?

Soluzione

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

Altre informazioni su ordinamento per chiavi »

Altri suggerimenti

Un modo che può essere più veloce, specialmente se la tua lista ha molti record, è usare operator.attrgetter (" count ") . Tuttavia, questo potrebbe essere eseguito su una versione pre-operatore di Python, quindi sarebbe bello avere un meccanismo di fallback. Potresti voler fare quanto segue, quindi:

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

I lettori dovrebbero notare che il metodo key =:

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

è molte volte più veloce dell'aggiunta di ricchi operatori di confronto agli oggetti. Sono stato sorpreso di leggere questo (pagina 485 di "Python in a Nutshell"). Puoi confermarlo eseguendo dei test su questo piccolo programma:

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

I miei test, molto minimi, mostrano che il primo ordinamento è più di 10 volte più lento, ma il libro dice che è solo circa 5 volte più lento in generale. Il motivo per cui dicono è dovuto all'algoritmo di ordinamento altamente ottimizzato usato in Python ( timsort ).

Tuttavia, è molto strano che .sort (lambda) sia più veloce del semplice vecchio .sort (). Spero che lo risolvano.

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

Approccio orientato agli oggetti

È buona norma rendere la logica di ordinamento degli oggetti, se applicabile, una proprietà della classe anziché incorporata in ogni istanza in cui è richiesto l'ordinamento.

Ciò garantisce coerenza ed elimina la necessità di codice del boilerplate.

Come minimo, è necessario specificare le operazioni __eq__ e __lt__ affinché funzioni. Quindi usa ordinato (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]

Sembra molto simile a un elenco di istanze del modello ORM di Django.

Perché non ordinarli su query in questo modo:

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

Aggiungi ricchi operatori di confronto alla classe di oggetti, quindi usa il metodo sort () dell'elenco.
Vedi confronto dettagliato in python .


Aggiorna : sebbene questo metodo funzioni, penso che la soluzione di Triptych sia più adatta al tuo caso perché molto più semplice.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top