2009-10-04 18 views
15

Muszę posortować listę Pythona z wieloma atrybutami. Można to zrobić w porządku rosnącym dla wszystkich atrybutów łatwoPython: sortowanie listy z wieloma atrybutami i kolejnością mieszaną

L.sort(key=operator.attrgetter(attribute)).... 

ale problemem jest to, że muszę używać mieszanych konfiguracje dla rosnącej/malejącej ... Mam do „naśladować” nieco SQL Order By gdzie możesz zrobić coś w stylu "nazwa ASC, rok DESC". Czy istnieje sposób, aby zrobić to łatwo w python bez konieczności zaimplementowania niestandardowej funkcji porównywania?

+3

@egatmur To pytanie jest starsze niż inne. Duplikat jest odwrotny. – Jesse

Odpowiedz

26

Jeśli atrybut numeryczny, masz to.

def mixed_order(a): 
    return (a.attribute1, -a.attribute2) 

someList.sort(key=mixed_order) 

Jeśli twoje atrybuty zawierają ciągi lub inne bardziej złożone obiekty, masz kilka możliwości.

Sposób .sort() jest stabilny: można zrobić wiele podań. To chyba najprostsze. Jest również niezwykle szybki.

def key1(a): return a.attribute1 
def key2(a): return a.attribute2 

someList.sort(key=key2, reverse=True) 
someList.sort(key=key1) 

Jeśli jest to jedyny rodzaj, można zdefiniować własne operatory porównania specjalnego przeznaczenia. Minimalnie potrzebujesz __eq__ i __lt__. Pozostałe cztery można wyprowadzić z tych dwóch za pomocą prostej logiki.

+0

dzięki! callint sort() wiele razy okazało się idealnym rozwiązaniem dla mnie! –

+0

Dzięki za odpowiedź! Po prostu trochę zamieszania dotyczące pierwszej części; czy zwrócenie krotki wykonuje sortowanie złożone o wyższych wartościach indeksu, które mają niższy priorytet? Domyślam się, że moje pytanie jest bardziej ogólne, jak zachowuje się 'cmp' przy podaniu dwóch krotek? Rozejrzałem się i nie mogę znaleźć tego udokumentowanego. –

+0

__eq__ można wyprowadzić z __lt__ używając prostej logiki. :) – Tony

5

Nie możesz, ale pisanie funkcji porównania jest łatwe:

def my_cmp(a, b): 
    return cmp(a.foo, b.foo) or cmp(b.bar, a.bar) 
L.sort(my_cmp) 
7

Niestandardowa funkcja uczyni Twój kod bardziej czytelnym. Jeśli masz wiele operacji sortowania i nie chcesz, aby stworzyć te funkcje, choć można użyć lambda:

L.sort(lambda x, y: cmp(x.name, y.name) or -cmp(x.year, y.year)) 
Powiązane problemy