Zabawy z sortowaniem

Raz na jakiś czas przydałoby się nam coś posortować. Jak wiadomo rodzajów sortowania jest wiele jednak nie o tym będzie ten wpis. My skupimy się raczej na dobrym wykorzystaniu tego co Python nam daje. Jest spora szansa, że mechanizmy wbudowane w język załatwią 80% twoich problemów. Moim zdaniem najlepiej uczyć się poprzez serię prostych i krótkich przykładów. Zatem do boju.

Sortowanie listy

Podaną listę lista1 = [4, 3, 6, 7, 3, 0, 9, 3, 6] posortuj w kolejności od największej do najmniejszej.

lista1 = [4, 3, 6, 7, 3, 0, 9, 3, 6]
lista1.sort(reverse=True)
print(lista1)

Skorzystaliśmy tu z metodysort” wbudowanej w listę. Dodatkowo ustawiliśmy flagęreverse” na ”True”, która implikuje kierunek sortowania. Domyślnie ”reverse” ustawione jest na ”False” co powoduje sortowanie od najmniejszej do największej. Warto pamiętać, że użycie metodysort” powoduje zmianę naszej oryginalnej listy.

Sortowanie krotki

Pewnie korciło by Cię by postąpić podobnie jak z listą. Niestety tak się nie da. Krotki (tuple) nie mają metodysort”. To dlatego, że jak wcześniej wspominaliśmy metoda ta powoduje zamianę oryginalnej kolekcji jaką poddajemy sortowaniu. Jak pewnie wiesz nie mamy takiej mocy by dokonać zmian na tupli bo jest ona niezmienna (immutable) – tak została zaprojektowana. Z pomocą przychodzi nam funkcjasorted”.

lista1 = (4, 3, 6, 7, 3, 0, 9, 3, 6)
#lista1.sort(reverse=True)tak sie nie da
lista1 = tuple(sorted(lista1))
print(lista1)

Output:

(0, 3, 3, 3, 4, 6, 6, 7, 9)

Jak widać funkcjasorted” nie modyfikuje sortowanej kolekcji. Zamiast tego zwraca już posortowaną kolekcję w postaci listy. No właśnie, aby być zgodnym z zadaniem przerobiliśmy naszą listę na tuplę. Oczywiście ty nie zawsze musisz postępować w ten sposób.

Sortowanie słownika

Sortowanie po kluczach

slownik = {7 : 'siedem', 1 : 'jeden', 4 : 'cztery'}
print(sorted(slownik)) # tak ale to robi liste posortowanych indeksow

Output:

[1, 4, 7]

Chyba nie do końca oczekiwaliśmy takiego efektu. To co udało się osiągnąć to lista posortowanych kluczy, która pewnie nie jest zbyt użyteczna. Spróbujmy zatem innego podejścia.

Sortowanie po kluczach ale pamiętając o wartościach

slownik = {7 : 'siedem', 1 : 'jeden', 4 : 'cztery'}

wynik = []
for key, value in sorted(slownik.items()):
    wynik.append((key, value))

print(wynik)

Output:

[(1, 'jeden'), (4, 'cztery'), (7, 'siedem')]

Tym razem sortowaniu nie poddaliśmy jedynie kluczy. Skorzystaliśmy z metodyitems” tak aby jednocześnie sortować klucze wraz z wartościami. Następnie przeiterowaliśmy się po naszej wynikowej liście by zapisać wyniki jako lista tupli klucz-wartość.

Sortowanie po wartościach

slownik = {7 : 'siedem', 1 : 'jeden', 4 : 'cztery'}

wynik = []
for key, value in sorted(slownik.items(), key=lambda x: x[1]):
    wynik.append((key, value))

print(wynik)

Output:

[(4, 'cztery'), (1, 'jeden'), (7, 'siedem')]

Zauważ jak niewiele zmian było potrzebne by zacząć sortować po wartościach. Skorzystaliśmy z drugiego parametru funkcjisorted” o nazwie ”key”. Parametr ten może przyjąć dowolną funkcję. Działa to tak, że każdy element z naszej kolekcji jest poddawany działaniu funkcji i dopiero jej wynik służy jako wartość do sortowania. W naszym przypadku ze wszystkich elementów będących krotkami klucz-wartość my skupiamy się tylko na drugim elemencie krotki, czyli wartości. Oczywiście funkcjasorted” dalej zwraca cała zawartość naszej oryginalnej kolekcji tyle, że posortowaną. Funkcja przekazana jako ”key” służy tylko do tymczasowego generowania wartości które będą sortowane by w odpowiednim miejscu ulokować dany element.

Czemu sortowanie słownika nie zwraca słownika

Do tej porty poddając sortowaniu kolekcję typu słownik (dict) jako wynik dostawaliśmy posortowaną listę. Oczywiście lista ta zawierała kluczewartości z naszego słownika, jednak nie był to posortowany słownik, a raczej posortowana lista. Zastanawiałeś się pewnie czemu nie da się posortować słownika tak samo jak robiliśmy to z listą. W przypadku listy wywoływaliśmy metodę sort i w magiczny sposób za chwile dysponowaliśmy już posortowaną kolekcją. Wcześniej mówiliśmy, że z tuplą te czary nie zadziałają bo tupla jest kolekcją niezmienną. Jednak słownik tak jak i listę możemy modyfikować. O co więc tu chodzi. Aby to zrozumieć trzeba troszkę dokładniej spojrzeć na nasz słownik. Otóż nasz słownik (dict) tak naprawdę powinien nosić nazwę słownik nieposortowany (unordered dict). Zatem nie posortowanie naszej kolekcji wynika po prostu ze specyfiki samego słownika. Poniekąd dzięki nie posortowaniu nasz słownik tak szybko może odwoływać się po kluczach do swoich elementów. Zatem moja propozycja jest taka:

from collections import OrderedDict

slownik = {7 : 'siedem', 1 : 'jeden', 4 : 'cztery'}


nowy_slownik = OrderedDict(sorted(slownik.items(), key=lambda x: x[1]))
print(nowy_slownik)
print(nowy_slownik[1])

Output:

OrderedDict([(4, 'cztery'), (1, 'jeden'), (7, 'siedem')])
jeden

Prawda, że ładne ? Skorzystaliśmy z innej kolekcjiOrderedDict”, by to w niej trzymać już posortowane po wartościach dane z naszego słownika. Jak widzisz dzięki temu dalej możemy się do nich odwoływać poprzez indeksy.