Opis sortowania w Pythonie można znaleźć w Sorting HOWTO w dokumentacji Pythona.
Python posiada wbudowaną funkcję sorted(), która z obiektu iterowalnego tworzy nową listę posortowaną.
Listy mają wbudowaną metodę do stabilnego sortowania elementów IN PLACE. Stosowany algorytm nosi nazwę timsort, a stworzył go Tim Peters w roku 2002 [Wikipedia]. Jest to algorytm hybrydowy, bazujący na merge sort i insertion sort. Jest też nazywany algorytmem adaptacyjnym. Algorytm timsort jest standardowym algorytmem sortowania w Pythonie od wersji 2.3. Stosowany jest także do sortowania macierzy w Java SE 7 i na platformie Android.
# Jeżeli L to lista, to mamy wywołanie postaci # L.sort(cmp=None, key=None, reverse=False) # Py2 # L.sort(/, *, key=None, reverse=False) # Py3, keywords only string_list.sort() # sortowanie listy napisów (duże litery najpierw) # Potrzebujemy case-insensitive sort. # Stary sposób - określamy funkcję porównującą dwa obiekty. string_list.sort(cmp=lambda x, y: cmp(x.lower(), y.lower())) # Nowy sposób (Py2.4) - podajemy klucz, czyli jakby sposób # patrzenia na obiekt. Nazwa "str" występuje jako nazwa klasy. # Sortowanie jest stabilne. string_list.sort(key=str.lower) # Sortowanie pod względem długości napisów, malejąco. string_list.sort(key=len, reverse=True) # Sortowanie obiektów względem atrybutów. student_list.sort(key=lambda student: student.grade) import operator student_list.sort(key=operator.attrgetter("grade")) # Sortowanie listy krotek względem pewnej pozycji. pair_list.sort(key=lambda pair: pair[1]) import operator pair_list.sort(key=operator.itemgetter(1)) # Sortowanie listy elementów L na bazie wartości ze słownika D. sorted(L, key=D.get)
# Transforming a comparison function to a key function. from functools import cmp_to_key # Py3.2+ alist.sort(key=cmp_to_key(cmp_function)) sorted(iterable, key=cmp_to_key(locale.strcoll)) # locale-aware sort order
W bardziej złożonych sytuacjach można korzystać ze schematu DSU (Decorate, Sort, Undecorate) [Receptury].
Istnieje ładne rozwiązanie w Recepturach (19.14, s. 737). Metoda sort() potrafi skorzystać z faktu, że podsekwencje są posortowane. Z drugiej strony, ta metoda działa ogólnie nawet dla nieposortowanych podsekwencji.
# Sortowanie przy założeniu, że sekwencje mieszczą się w pamięci. # Usage: res = smallmerge(seq1, seq2, seq3) def smallmerge(*subsequences): result = [] for seq in subsequences: result.extend(seq) result.sort() return result
Jeżeli sekwencje są duże (nie mieszczą się w pamięci), to proponowane rozwiązanie korzysta z generatorów i sterty.
from operator import attrgetter class Person: def __init__(self, name, money=0): self.name = name self.money = money def __repr__(self): return "Person({0!r}, {1})".format(self.name, self.money) persons = [] persons.append(Person("Adam", 50)) persons.append(Person("Edek", 10)) persons.append(Person("Lolek", 20)) persons.append(Person("Bolek", 10)) # Sortowanie wg nazwiska. persons.sort(key=lambda x: x.name) # atrybut zaszyty na stałe persons.sort(key=lambda x: getattr(x, "name")) # atrybut można przekazać do sortowania persons.sort(key=attrgetter("name")) # [Person('Adam', 50), Person('Bolek', 10), Person('Edek', 10), Person('Lolek', 20)] # Sortowanie wg zarobków. persons.sort(key=lambda x: x.money) persons.sort(key=lambda x: getattr(x, "money")) persons.sort(key=attrgetter("money")) # [Person('Edek', 10), Person('Bolek', 10), Person('Lolek', 20), Person('Adam', 50)] # Sortowanie wg zarobków, potem nazwiska. persons.sort(key=lambda x: (x.money, x.name)) persons.sort(key=lambda x: (getattr(x, "money"), getattr(x, "name"))) persons.sort(key=attrgetter("money", "name")) # Zwraca krotkę (person.money, person.name). # [Person('Bolek', 10), Person('Edek', 10), Person('Lolek', 20), Person('Adam', 50)]
Jeżeli w Pythonie musimy posortować dane, to najlepiej znaleźć sposób na wykorzystanie wbudowanej w listy Pythona metody sort(). Często stosowanym rozwiązaniem jest implementacja wzorca DSU (Decorate, Sort, Undecorate; dekoruj-sortuj-usuń dekorację), opisanego w [Receptury]. Wzorzec opiera się na tym, że w Pythonie sekwencje są porównywane leksykograficznie.
# Wzorzec DSU na przykładzie sortowania stringów # bez uwzględniania wielkości liter. def case_insensitive_sort(string_list): alist = [(x.lower(), i, x) for (i, x) in enumerate(string_list)] # dekoruj # Użycie 'i' daje sortowanie stabilne, a także pozwala sortować elementy, # które nie mogą być sortowane bezpośrednio, np. liczby zespolone. alist.sort() # sortuj #return [t[2] for t in alist] # usuń dekorację return [x for (low, i, x) in alist] # usuń dekorację