2013-01-13 13 views
7

Sono nuovo alla programmazione e in questo momento sto scrivendo una classifica in Python. Vorrei classificare il mio campionato per primi punti, e se ci sono due squadre con gli stessi punti vorrei classificarle per differenza reti, e se hanno la stessa differenza reti mi piacerebbe ordinare per nome.Ordinamento per condizioni multiple in python

La prima condizione è abbastanza facile e sta lavorando dal seguente:

table.sort(reverse=True, key=Team.getPoints) 

Come inserisco le seguenti due condizioni?

+0

Probabilmente vorrete leggere [Python Sorting HowTo] (http://wiki.python.org/moin/HowTo/Sorting/). (In realtà, ho difficoltà a caricarlo al momento, ma c'è sempre [Google Cache] (http://webcache.googleusercontent.com/search?q=cache:GjjYVDIjFi0J:wiki.python.org/moin/HowTo/ Ordinamento/+ & cd = 1 & hl = it & ct = clnk & gl = us & client = firefox-a)) – kojiro

+0

Wow. Ho esattamente lo stesso compito: ordinare squadre in campionato) – imkost

+0

Possibile duplicato di [Ordinamento di un elenco Python in base a due criteri] (http://stackoverflow.com/questions/5212870/sorting-a-python-list-by-two-criteria) – GingerPlusPlus

risposta

4

Ordinare prima l'elenco per nome, quindi ordinare di nuovo in base alla differenza di punteggio. Python sort è stabile, il che significa che manterrà l'ordine degli elementi che sono uguali.

10

Abbia la funzione key restituire una tupla, con elementi in ordine di priorità decrescente:

table.sort(reverse=True, key=lambda team: (Team.getPoints(team), 
              Team.getGoalDifference(team), 
              Team.getName(team)) 

In alternativa, si potrebbe ricordare un factoid da algoritmi di 101, e fare uso del fatto .sort() è un stabile ordina, e quindi non cambia l'ordine relativo degli articoli in una lista se li confronta come uguali. Ciò significa che è possibile ordinare tre volte, in ordine crescente di priorità:

table.sort(reverse=True, key=Team.getName) 
table.sort(reverse=True, key=Team.getGoalDifference) 
table.sort(reverse=True, key=Team.getPoints) 

Questo sarà più lento, ma consente di specificare facilmente se ogni passo dovrebbe essere fatto in reverse o meno. Questo può essere fatto senza l'ordinamento più passaggi utilizzando cmp_to_key(), ma la funzione di confronto sarebbe banale, qualcosa di simile:

def team_cmp(t1, t2): 
    for key_func, reverse in [(Team.getName, True), 
           (Team.getGoalDifference, True), 
           (Team.getPoints, True)]: 
     result = cmp(key_func(t1), key_func(t2)) 
     if reverse: result = -result; 
     if result: return result 
    return 0 

table.sort(functools.cmp_to_key(team_cmp)) 

(Disclaimer:. Quanto sopra è scritto dalla memoria, non testato) L'enfasi è sulla "senza più passaggi" , che non implica necessariamente "più veloce". L'overhead dalla funzione comparatore e cmp_to_key(), entrambi implementati in Python (al contrario di list.sort() e operator.itemgetter(), che dovrebbe far parte del core C) è probabile che sia significativo.

Come parte, non è necessario creare funzioni fittizie per passare ai parametri key. È possibile accedere direttamente l'attributo, utilizzando:

table.sort(key=lambda t: t.points) 

o l'involucro attrgetter esercente:

table.sort(key=attrgetter('points')) 
+1

Il primo non è forse un po 'diverso dal secondo? Si applica 'reverse = True' all'intera tupla, mentre la versione in tre passaggi la applica solo ai punti. – DSM

+0

@DSM È, stavo cercando di fare un esempio che * puoi * cambiare l'ordine per i vari passaggi, ma immagino che non sia ovvio e confuso. – millimoose

+0

Bene, non potresti semplicemente usare '* -1' per invertire un campo? –

0

pitone algoritmo di ordinamento è Timsort che, come sottolinea ACEfanatic02, è stable che significa ordine preservata. This link ha una bella spiegazione visiva di come funziona.

+0

E così Tim Peters è diventato immortalato. – millimoose