Jedną z kluczowych zalet języka Python jest jego klarowność i prostota składni. Praca z nim staje się intuicyjna, ponieważ w swojej standardowej bibliotece oferuje bogaty zbiór użytecznych narzędzi. Wśród nich na szczególną uwagę zasługuje funkcja `sorted`.
Jej zadaniem jest porządkowanie elementów w zbiorze iterowalnym zgodnie z ustalonym kryterium. W sytuacji, gdyby ta funkcja nie istniała, konieczne byłoby samodzielne pisanie kodu implementującego algorytmy sortowania, takie jak np. sortowanie bąbelkowe czy przez wstawianie. To często okazuje się zadaniem skomplikowanym, lecz Python dostarcza nam prostsze rozwiązanie, które zostanie szczegółowo omówione w tym artykule.
Wprowadzenie do funkcji `sorted`
Funkcja `sorted` to mechanizm w Pythonie, który umożliwia sortowanie elementów należących do zbiorów iterowalnych. Zbiór iterowalny to dowolna sekwencja, po której można iterować, czyli przechodzić kolejno przez jej elementy. Przykładami takich struktur są łańcuchy znaków, listy, krotki i zbiory. Często elementy te nie są uporządkowane, a sortowanie ma na celu ich uszeregowanie według określonego porządku. Uporządkowanie elementów przynosi wiele korzyści:
- Wyszukiwanie konkretnej wartości staje się szybsze i bardziej wydajne, szczególnie przy użyciu algorytmów takich jak wyszukiwanie binarne. Warto jednak pamiętać, że wyszukiwanie binarne wymaga, aby zbiór danych był najpierw posortowany.
- Ułatwia prezentację danych. Czasami użytkownicy chcą przeglądać informacje w określonej kolejności, np. od najniższej do najwyższej ceny lub od najnowszego do najstarszego wpisu. W takiej sytuacji potrzebujemy metody, która pozwoli na uporządkowanie listy wartości.
- Pomaga w analizie statystycznej, np. podczas poszukiwania najczęściej występującej wartości w danym zbiorze. Proces ten jest znacznie prostszy, gdy wartości są już posortowane.
Przewodnik po stosowaniu funkcji `sorted`
Jak już wspomniano, funkcja `sorted` współpracuje z wszystkimi obiektami iterowalnymi. Co istotne, w wyniku jej działania otrzymujemy listę, która zawiera posortowane elementy. Warto o tym pamiętać – chociaż wejściem może być dowolny zbiór iterowalny, wyjściem zawsze będzie lista.
Składnia funkcji `sorted`
Sygnatura funkcji `sorted` wygląda następująco:
sorted(iterable, key=None, reverse=False)
Jak widzimy, jedynym obowiązkowym argumentem jest zbiór iterowalny, który chcemy posortować.
Kolejnym argumentem jest `key`. Jest to funkcja, która służy do przekształcenia każdego elementu zbioru iterowalnego w wartość, która będzie używana podczas porównywania i sortowania. To rozwiązanie okazuje się szczególnie przydatne w przypadku sortowania listy słowników. Wartość domyślna argumentu to `None`, co oznacza, że jeśli nie zostanie on jawnie określony, nie zostanie zastosowana żadna funkcja przekształcająca.
Ostatni argument, `reverse`, jest argumentem logicznym. Gdy ustawimy go na `True`, elementy zostaną posortowane w kolejności odwrotnej.
W kolejnej części artykułu przejdziemy do praktycznych przykładów, aby zaprezentować, jak stosować tę funkcję.
Przykłady użycia funkcji `sorted`
Lista liczb
Najprostszym przypadkiem, w którym możemy użyć funkcji `sorted` jest sortowanie listy liczb. Rozważmy poniższy przykład:
# Lista nieposortowanych wartości numbers = [8, 4, 3, 9, 2, 0, 3] # Sortowanie liczb sorted_numbers = sorted(numbers) # Wyświetlenie posortowanych wartości print(sorted_numbers)
W wyniku otrzymamy:
[0, 2, 3, 3, 4, 8, 9]
Jak widać, wartości zostały posortowane w porządku rosnącym. Jeśli chcielibyśmy je posortować w porządku malejącym, wystarczy ustawić wartość argumentu `reverse` na `True`. Zatem linijka 4 w powyższym kodzie powinna wyglądać następująco:
sorted_numbers = sorted(numbers, reverse=True)
W efekcie zmodyfikowany program da nam taki wynik:
[9, 8, 4, 3, 3, 2, 0]
Lista ciągów znaków
Funkcja `sorted` radzi sobie nie tylko z liczbami. Możemy jej także użyć do sortowania ciągów znaków. W przypadku sortowania listy ciągów, porównywane są pierwsze znaki tych ciągów. Porównania opierają się na wartościach ASCII znaków. Przykładowo, łańcuch „hello” pojawi się przed łańcuchem „world”, ponieważ wartość ASCII litery „h” wynosi 104, czyli jest mniejsza niż wartość ASCII litery „w” (119).
Jeśli co najmniej dwa ciągi mają taki sam pierwszy znak, porównywane są kolejne znaki, aż do ustalenia kolejności. Poniżej znajduje się przykład kodu, który sortuje listę imion:
# Tworzenie listy imion members_list = ['bob', 'dave', 'charlie', 'alice'] # Sortowanie imion sorted_members_list = sorted(members_list) # Wyświetlenie imion print(sorted_members_list)
W wyniku otrzymamy:
['alice', 'bob', 'charlie', 'dave']
Ponieważ wykorzystywane są wartości ASCII, kolejność łańcuchów zależy od tego, który znak występuje jako pierwszy w tabeli ASCII. Przykładowo, wielka litera pojawi się przed małą literą, ponieważ wielkie litery w tabeli ASCII występują przed małymi. Dla informacji, pełna tabela ASCII znajduje się poniżej:
Źródło: commons.wikimedia.org
Inne struktury iterowalne – łańcuchy, krotki i zbiory
Jak już wspomniano, funkcja `sorted` działa z różnymi typami obiektów iterowalnych. Zasady sortowania elementów w tych strukturach są takie same jak w przypadku list. Poniżej znajduje się przykład:
# Wyświetlanie posortowanego łańcucha print(sorted("dijkstra")) # Wyświetlanie posortowanej krotki print(sorted((3, 4, 2, 1, 5, 0))) # Wyświetlanie posortowanego zbioru print(sorted(set([4, 5, 5, 1, 3, 8, 9])))
Wynik tego kodu będzie następujący:
['a', 'd', 'i', 'j', 'k', 'r', 's', 't'] [0, 1, 2, 3, 4, 5] [1, 3, 4, 5, 8, 9]
Jak widzimy, w każdym przypadku wynikiem jest lista.
Lista słowników
Funkcję `sorted` możemy wykorzystać również do sortowania listy słowników. W tym przypadku sortowanie staje się nieco bardziej skomplikowane. Wynika to z faktu, że słownik, w przeciwieństwie do liczb czy łańcuchów znaków, posiada wiele atrybutów, z których każdy może być istotny podczas porównywania.
Aby posortować słowniki, należy zdefiniować funkcję, która podsumuje cały słownik do pojedynczej wartości, która posłuży do porównania. Funkcja ta jest przekazywana do funkcji `sorted` jako argument `key`. Ilustruje to poniższy przykład:
people = [ { 'name': 'Alice', 'age': 27 }, { 'name': 'Bob', 'age': 23 }, { 'name': 'Charlie', 'age': 25} ] people_sorted_by_age = sorted(people, key=lambda person: person['age']) print(people_sorted_by_age)
W tym przykładzie mamy trzy osoby, reprezentowane przez obiekty typu słownik. Każdy z nich posiada atrybuty `name` (imię) i `age` (wiek). Chcemy posortować osoby według wieku. Dlatego, wywołując funkcję `sorted`, przekazujemy funkcję jako argument `key`.
Funkcja ta przyjmuje obiekt słownika reprezentujący osobę i zwraca jej wiek. Wartość zwracana przez tę funkcję klucza jest używana do sortowania. W ten sposób cały słownik został sprowadzony do prostej liczby całkowitej, którą można porównywać. Dla uproszczenia, do zdefiniowania argumentu `key` została użyta funkcja lambda.
Uruchomienie kodu spowoduje wyświetlenie następującego wyniku:
[{'name': 'Bob', 'age': 23}, {'name': 'Charlie', 'age': 25}, {'name': 'Alice', 'age': 27}]
Przypadki użycia argumentu `key`
Argument `key` nie jest wykorzystywany tylko podczas sortowania list słowników. Możemy go użyć w przypadku sortowania elementów dowolnego typu. Jego zastosowanie polega na dostarczeniu klucza, który będzie używany podczas sortowania wartości. Oto przykładowe scenariusze użycia:
- Sortowanie wartości na podstawie długości, definiując funkcję klucza, która przyjmuje wartość i zwraca jej długość.
- Sortowanie ciągów znaków na liście bez uwzględniania wielkości liter. W tym celu każdy ciąg w liście można przekształcić na małe litery, definiując funkcję klucza, która przyjmuje ciąg i zwraca jego wersję pisaną małymi literami.
- Sortowanie wartości na podstawie złożonej wartości, która łączy w sobie wartości z innych elementów.
Złożoność czasowa funkcji `sorted`
Funkcja `sorted` ma złożoność czasową O(n log n), gdzie `n` to liczba elementów w zbiorze wejściowym. Taka złożoność wynika z faktu, że funkcja używa algorytmu Timsort, będącego hybrydowym algorytmem sortowania bazującym na sortowaniu przez scalanie i sortowaniu przez wstawianie.
Złożoność pamięciowa funkcji wynosi O(n), gdzie `n` to liczba elementów w zbiorze wejściowym. Jest to spowodowane tym, że funkcja tworzy i zwraca nową listę.
Funkcja `sorted` a metoda `sort`
Innym sposobem sortowania wartości jest użycie metody `sort`. W tej sekcji omówimy najważniejsze różnice pomiędzy funkcją `sorted` a metodą `sort`.
- Metoda `sort` modyfikuje listę na której jest wywoływana, podczas gdy funkcja `sorted` tworzy nową listę i ją zwraca.
- Ponieważ metoda `sort` wykonuje modyfikacje na miejscu, wymaga, aby jej wejściem była lista. Natomiast funkcja `sorted` może przyjmować jako wejście dowolny obiekt iterowalny, na podstawie którego tworzy nową listę, którą następnie modyfikuje i zwraca.
Podsumowanie
W tym artykule omówiliśmy szczegółowo funkcję `sorted` – czym jest, jak z niej korzystać i jakie przyjmuje argumenty. Przedstawiliśmy także wiele przykładów użycia tej funkcji, analizując jej złożoność czasową oraz porównując ją z metodą `sort`.
Zachęcamy do zapoznania się z naszym kolejnym artykułem, poświęconym funkcji `sum` w Pythonie.