2016-01-14 19 views
9

Próbuję uporządkować listę krotek, takie jak:Sortowanie na różnych poziomach w Pythonie

[('Pineapple', 1), ('Orange', 3), ('Banana', 1), ('Apple', 1), ('Cherry', 2)] 

lista posortowana powinno być:

[('Orange', 3), ('Cherry', 2), ('Apple', 1), ('Banana', 1), ('Pineapple', 1)] 

Więc tutaj 1-ci lista powinna być klasyfikowane na podstawie tuple[1] w porządku malejącym, a następnie, jeśli wartości tuple (tuple[1]) są zgodne pod względem Apple, Banana & Pineapple - lista powinna być dalej sortowana na podstawie tuple[0] w ascendi w porządku.

Próbowałem możliwe ways-

top_n.sort(key = operator.itemgetter(1, 0), reverse = True) 
# Output: [(Orange, 3), (Cherry, 2), (Pineapple, 1), (Banana, 1), (Apple, 1)] 

jak "reverse = True", ananas, banan potem ...

końcu musiał wymyślić rozwiązanie:

top_n.sort(key = operator.itemgetter(0), reverse = False) 
top_n.sort(key = operator.itemgetter(1), reverse = True) 

Czy istnieje lepszy sposób, aby uzyskać rozwiązanie, takie jak moje pierwsze podejście. Próbuję dowiedzieć się więcej o Pythonie, szukając w ten sposób takiego rozwiązania.

+0

Właściwie można po prostu zrobić: 'top_n.sort(); top_n.sort (key = itemgetter (1), reverse = True) '. Ponieważ 'reverse = False' jest wartością domyślną. Używanie 'itemgetter (0)' nie ma zbytniego sensu, ponieważ sekwencje są już sortowane przez pierwszy element, więc możesz po prostu uniknąć użycia 'key'. – Bakuriu

+0

@Bakuriu: Tak! Prawdziwe. Dzieki za sugestie. –

Odpowiedz

2

W twoim przypadku, rozwiązanie Martijn Pieters jest chyba najlepszy, ale rozważa, co byś zrobił, gdyby trzeba było zrobić to dla dowolnej liczby parametrów, i trzeba zrobić kilka rosnąco i kilka zstępujących.

To podejście tworzy funkcję generowania indeksu sortowania w locie. Wywołanie getortfunction z listą krotek do sortowania oraz lista zawierająca indeksy i jeśli powinny być w odwrotnej kolejności (na przykład (2,True) oznacza drugi indeks w odwrotnej kolejności), zwraca funkcję, która tworzy indeks sortowania dla obiektu. Jest to dość brzydki, ale wszechstronny.

def getsortfunction(values,indices): 
    sorts = [sorted(list(set(x[indices[i][0]] for x in values)),reverse=indices[i][1]) for i in range(len(indices))] 
    def sortfunction(y): 
     return tuple(sorts[i].index(y[indices[i][0]]) for i in range(len(indices))) 
    return sortfunction 

Przykłady

a = [('Pineapple',1),('Orange',3),('Banana',1),('Apple',1),('Cherry',2)] 
# sort a by index 1 first (in reverse order) and then by index 0 in non-reverse order 
b = sorted(a,key=getsortfunction(a,[(1,True),(0,False)])) # gives desired list 

z dodatkowych kryteriów

c = [('Pineapple',1,'Hawaii'),('Orange',3,'Florida'),('Banana',1,'Hawaii'),('Apple',1,'Washington'),('Cherry',2,'Washington')] 
# sort first by number (in reverse order) then by state, and finally by fruit 
d = sorted(c,key=getsortfunction(c,[(1,True),(2,False),(0,False)])) 

# sort c first by number (in reverse order), then by fruit, ignoring state 
e = sorted(c,key=getsortfunction(c,[(1,True),(0,False)])) 

getsortfunction najpierw buduje zagnieżdżony listę unikatowych wartości w kolejności i zwraca funkcję, która odwzorowuje każdą wartość mają być klasyfikowane do krotka numeryczna podająca jej indeksy na posortowanej liście wartości.

Największą zaletą tego jest to, że można określić kryteria sortowania w środowisku wykonawczym (na przykład z żądań użytkownika).

+0

Tego rodzaju rozwiązanie próbowałem, ale pomyślałem, że może przesadzam (nowość w Pythonie) i zatrzymałem to. Choć to trochę brzydkie, uważam, że jest to skuteczne rozwiązanie. Dziękuję Ci! –

13

Niech twój klucz zwróci krotkę wartości numerycznej zanegowana, a następnie ciąg znaków. Przez negując, numery zostaną posortowane w kolejności malejącej, a struny są sortowane w kolejności rosnącej:

top_n.sort(key=lambda t: (-t[1], t[0])) 

Tak, to jest bit hack, ale działa wszędzie trzeba sortować według dwóch kryteriów w przeciwnych wskazówki, a jednym z tych kryteriów jest numeryczny.

Demo:

>>> top_n = [('Pineapple', 1), ('Orange', 3), ('Banana', 1), ('Apple', 1), ('Cherry', 2)] 
>>> sorted(top_n, key=lambda t: (-t[1], t[0])) 
[('Orange', 3), ('Cherry', 2), ('Apple', 1), ('Banana', 1), ('Pineapple', 1)] 
+1

Jedynym problemem z tym rozwiązaniem jest to, że negacja działa tylko dla liczb całkowitych. Nie mogę zaproponować niczego lepszego, moje rozwiązanie było takie samo. – fodma1

+0

Co jeśli oba argumenty krotki były ciągami? – Arman

+3

@Arman: dalsze hakowanie: zamień łańcuch na ciąg zanegowanych liczb całkowitych ('[-chr (c) dla c w łańcuchu znaków]'). –

Powiązane problemy