2013-01-13 9 views
7

Jestem nowy w programowaniu i teraz piszę tabelę lig w pythonie. Chciałbym posortować swoją ligę według pierwszych punktów, a jeśli są dwa zespoły z tymi samymi punktami, chciałbym posortować je według różnicy bramek i jeśli mają tę samą różnicę bramkową, chciałbym posortować je według nazwy.Sortowanie według wielu warunków w pythonie

Pierwszym warunkiem jest całkiem proste i pracuje brzmienie:

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

jak mogę wstawić dwa następujące warunki?

+0

Prawdopodobnie chcesz przeczytać [Python Sorting HowTo] (http://wiki.python.org/moin/HowTo/Sorting/). (W tej chwili mam problem z jego załadowaniem, ale zawsze jest [Google Cache] (http://webcache.googleusercontent.com/search?q=cache:GjjYVDIjFi0J:wiki.python.org/moin/HowTo/ Sortowanie/+ i cd = 1 & hl = en & ct = clnk & gl = us & client = firefox-a)) – kojiro

+0

Wow. Mam dokładnie to samo zadanie: sortowanie drużyn w lidze) – imkost

+0

Możliwy duplikat [Sortowania listy Pythona według dwóch kryteriów] (http://stackoverflow.com/questions/5212870/sorting-a-python-list-by-two-criteria) – GingerPlusPlus

Odpowiedz

4

Najpierw posortuj listę według nazwy, a następnie sortuj ponownie według różnicy wyników. Python's sort jest stabilny, co oznacza, że ​​zachowa porządek porównywanych elementów.

10

posiadają funkcję key powrócić krotki, z elementami w kolejności priorytetów maleje:

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

Alternatywnie, można zapamiętać factoid z algorytmami 101 i skorzystać z faktu .sort() jest stabilny sortuj, a zatem nie zmieniaj względnej kolejności pozycji na liście, jeśli są one porównywane jako równe. Oznacza to, że można sortować trzykrotnie, w porządku rosnącym pierwszeństwa:

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

ten będzie wolniejszy, ale pozwala łatwo określić, czy każdy krok należy zrobić w reverse czy nie. Można to zrobić bez wielokrotnego sortowania przechodzi przy użyciu cmp_to_key(), ale funkcja komparator będzie nietrywialne, coś jak:

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

(Zastrzeżenie:. Wyżej jest napisane z pamięci, niesprawdzone) Nacisk jest na „bez wielu przejściach” , co niekoniecznie oznacza "szybciej". Narzut z funkcji komparatora i cmp_to_key(), które są zaimplementowane w Pythonie (w przeciwieństwie do list.sort() i operator.itemgetter(), które powinny stanowić część C core) prawdopodobnie będzie znaczący.

Odkładając na bok, nie trzeba tworzyć fałszywych funkcji, aby przejść do parametrów key. Można uzyskać dostęp atrybut bezpośrednio z:

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

lub owijka attrgetter operatora:

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

Czy ta pierwsza nie różni się od drugiej? Stosuje on 'reverse = True' do całej krotki, podczas gdy wersja trzystopniowa stosuje ją tylko do punktów. – DSM

+0

@ DS To jest, próbowałem zrobić przykład, że * możesz * zmienić kolejność dla różnych kroków, ale myślę, że to nie jest oczywiste i mylące. – millimoose

+0

Cóż, czy nie możesz użyć '* -1' do odwrócenia pola? –

0

Pythona algorytm sortowania jest Timsort które jako ACEfanatic02 wskazuje to stable czyli porządek jest zachowana. This link ma ładne wizualne wyjaśnienie, jak to działa.

+0

I tak Tim Peters został unieśmiertelniony. – millimoose

Powiązane problemy