Jaka jest różnica między `sorted (list)` vs `list.sort ()`?


194

list.sort()sortuje listę i zastępuje oryginalną listę, a sorted(list)zwraca posortowaną kopię listy bez zmiany oryginalnej listy.

  • Kiedy jedno jest preferowane?
  • Który jest bardziej wydajny? O ile?
  • Czy po wykonaniu można przywrócić listę do stanu nieposortowanego list.sort()?

4
Uważaj, jeśli (przypadkowo) wywołujesz sorted()argument ciągu, ale uważasz, że to lista, otrzymasz wynik listy, a nie ciąg : nie sorted("abcd", reverse=True)daje['d', 'c', 'b', 'a']"dcba"
— smci

Odpowiedzi:


316

sorted()zwraca nową posortowaną listę, pozostawiając nienaruszoną oryginalną listę. list.sort()sortuje listę w miejscu , mutując indeksy listy i zwraca None(jak wszystkie operacje w miejscu).

sorted()działa na dowolnych iterowalnych, nie tylko listach. Ciągi, krotki, słowniki (dostaniesz klucze), generatory itp., Zwracając listę zawierającą wszystkie posortowane elementy.

  • Użyj, list.sort()jeśli chcesz zmutować listę, sorted()gdy chcesz ponownie posortować nowy obiekt. Zastosowanie sorted()gdy chcemy uporządkować coś, co jest iterable, a nie lista jeszcze .

  • W przypadku list list.sort()jest szybszy niż sorted()dlatego, że nie musi tworzyć kopii. W przypadku innych iteracji nie masz wyboru.

  • Nie, nie możesz odzyskać oryginalnych pozycji. Po zadzwonieniu list.sort()oryginalne zamówienie zniknęło.


6
Zasadniczo, gdy funkcja python zwraca None, jest to znak, że operacje są wykonywane w miejscu, dlatego kiedy chcesz wydrukować list.sort(), zwraca None.
— user1767754,

45

Jaka jest różnica między sorted(list)vs list.sort()?

  • list.sort mutuje listę w miejscu i zwraca None
  • sorted przyjmuje dowolną iterowalną i zwraca posortowaną nową listę.

sorted jest równoważne z tą implementacją Pythona, ale wbudowana funkcja CPython powinna działać wymiernie szybciej, ponieważ jest napisana w C:

def sorted(iterable, key=None):
    new_list = list(iterable)    # make a new list
    new_list.sort(key=key)       # sort it
    return new_list              # return it

kiedy użyć którego?

  • Użyj, list.sortgdy nie chcesz zachować oryginalnej kolejności sortowania (dzięki temu będziesz mógł ponownie użyć listy w miejscu) i gdy jesteś jedynym właścicielem listy (jeśli lista jest współdzielona przez inny kod, a ty mutuj go, możesz wprowadzić błędy, w których używana jest ta lista).
  • Użyj, sortedgdy chcesz zachować oryginalną kolejność sortowania lub gdy chcesz utworzyć nową listę, do której należy tylko kod lokalny.

Czy oryginalne pozycje listy można pobrać po list.sort ()?

Nie - chyba że sam wykonałeś kopię, informacje te zostaną utracone, ponieważ sortowanie odbywa się na miejscu.

„A który jest szybszy? A o ile szybszy?”

Aby zilustrować karę tworzenia nowej listy, użyj modułu timeit, oto nasza konfiguracja:

import timeit
setup = """
import random
lists = [list(range(10000)) for _ in range(1000)]  # list of lists
for l in lists:
    random.shuffle(l) # shuffle each list
shuffled_iter = iter(lists) # wrap as iterator so next() yields one at a time
"""

A oto nasze wyniki dla listy losowo ułożonych 10000 liczb całkowitych, jak widzimy tutaj, obaliliśmy starszy mit dotyczący kosztów tworzenia listy :

Python 2.7

>>> timeit.repeat("next(shuffled_iter).sort()", setup=setup, number = 1000)
[3.75168503401801, 3.7473005310166627, 3.753129180986434]
>>> timeit.repeat("sorted(next(shuffled_iter))", setup=setup, number = 1000)
[3.702025591977872, 3.709248117986135, 3.71071034099441]

Python 3

>>> timeit.repeat("next(shuffled_iter).sort()", setup=setup, number = 1000)
[2.797430992126465, 2.796825885772705, 2.7744789123535156]
>>> timeit.repeat("sorted(next(shuffled_iter))", setup=setup, number = 1000)
[2.675589084625244, 2.8019039630889893, 2.849375009536743]

Po kilku opiniach zdecydowałem, że pożądany będzie kolejny test o różnych cechach. Tutaj podaję tę samą losowo uporządkowaną listę o długości 100 000 dla każdej iteracji 1000 razy.

import timeit
setup = """
import random
random.seed(0)
lst = list(range(100000))
random.shuffle(lst)
"""

Interpretuję różnicę tego większego rodzaju pochodzącą z kopiowania wspomnianego przez Martijna, ale nie dominuje ona do punktu podanego w starszej, bardziej popularnej odpowiedzi tutaj, tutaj wzrost czasu wynosi tylko około 10%

>>> timeit.repeat("lst[:].sort()", setup=setup, number = 10000)
[572.919036605, 573.1384446719999, 568.5923951]
>>> timeit.repeat("sorted(lst[:])", setup=setup, number = 10000)
[647.0584738299999, 653.4040515829997, 657.9457361929999]

Uruchomiłem również powyższe na znacznie mniejszym formacie i zobaczyłem, że nowa sortedwersja kopii nadal zajmuje około 2% dłuższy czas działania na długości 1000.

Poke również uruchomił swój własny kod, oto kod:

setup = '''
import random
random.seed(12122353453462456)
lst = list(range({length}))
random.shuffle(lst)
lists = [lst[:] for _ in range({repeats})]
it = iter(lists)
'''
t1 = 'l = next(it); l.sort()'
t2 = 'l = next(it); sorted(l)'
length = 10 ** 7
repeats = 10 ** 2
print(length, repeats)
for t in t1, t2:
    print(t)
    print(timeit(t, setup=setup.format(length=length, repeats=repeats), number=repeats))

Znalazł dla sortowania według długości 1000000, (uruchomił 100 razy) podobny wynik, ale tylko o około 5% wzrost w czasie, oto wynik:

10000000 100
l = next(it); l.sort()
610.5015971539542
l = next(it); sorted(l)
646.7786222379655

Wniosek:

Duża lista sortowana przy sortedtworzeniu kopii prawdopodobnie zdominuje różnice, ale samo sortowanie zdominuje operację, a uporządkowanie kodu wokół tych różnic byłoby przedwczesną optymalizacją. Użyłbym, sortedgdy potrzebuję nowej posortowanej listy danych, i użyłbym, list.sortgdy potrzebowałem posortować listę w miejscu, i pozwolić mi określić moje wykorzystanie.


4
Konfiguracja generatora jest dobra, ale nie wyciągnę wniosku, że zbyt szybko rozwaliłeś mit. Pozostaje faktem, że sorted()należy przydzielić nowy obiekt listy i skopiować odniesienia; reszta ścieżek kodu jest identyczna. Sprawdź, czy możesz uruchomić te same testy z większymi listami. Porównaj to z tworzeniem kopii list i sprawdź, czy możesz odtworzyć znalezione różnice itp.
— Martijn Pieters

11

Główną różnicą jest to, że sorted(some_list)zwraca nowylist :

a = [3, 2, 1]
print sorted(a) # new list
print a         # is not modified

i some_list.sort(), sortuje listę w lokalu :

a = [3, 2, 1]
print a.sort() # in place
print a         # it's modified

Pamiętaj, że ponieważ a.sort()nic nie zwraca, print a.sort()zostanie wydrukowane None.


Czy po list.sort () można pobrać oryginalne pozycje listy?

Nie, ponieważ modyfikuje oryginalną listę.


1
print a.sort()nic nie wydrukuje.
— Burhan Khalid

1
Wydrukuje None, wyjaśnię to.
— Christian

1

Funkcja .sort () przechowuje wartość nowej listy bezpośrednio w zmiennej listy; więc odpowiedź na twoje trzecie pytanie brzmiałaby NIE. Również jeśli zrobisz to za pomocą sortowania (listy), możesz go użyć, ponieważ nie jest przechowywany w zmiennej listy. Czasami również metoda .sort () działa jako funkcja lub mówi, że pobiera w niej argumenty.

Musisz przechowywać wartość posortowanej (listy) w zmiennej jawnie.

Również w przypadku krótkiego przetwarzania danych prędkość nie będzie różnicy; ale dla długich list; powinieneś bezpośrednio użyć metody .sort () do szybkiej pracy; ale znów staniecie wobec nieodwracalnych działań.


„Funkcja .sort () przechowuje wartość nowej listy bezpośrednio w zmiennej listy” Huh? Jaka nowa lista? Nie ma nowej listy. list.sort()Metoda sortuje przedmiot listy na miejscu.
— PM 2, dzwoni

Co to ma znaczyć? „czasami metoda .sort () działa jako funkcja lub mówi, że pobiera w niej argumenty.”
— PM 2, dzwoni

Nowa lista ma na myśli zmodyfikowaną listę, a .sort () przechowuje tę zmodyfikowaną listę w tej samej zmiennej.
— Vicrobot,

Tak, absolutnie czasami .sort()metoda pobiera argument i działa jako funkcja. Nazywamy to również metodą, ponieważ jest to atrybut typu danych listy.
— Vicrobot,

Jeśli w mojej koncepcji jest jakaś pomyłka, powiedz mi, że jej szukam i poprawię swoje koncepcje, a także moją odpowiedź. Dzięki
— Vicrobot,

1

Oto kilka prostych przykładów, które pokazują różnicę w działaniu:

Zobacz listę liczb tutaj:

nums = [1, 9, -3, 4, 8, 5, 7, 14]

Dzwoniąc sortedna tę listę, sortedzrobi kopię listy. (Oznacza to, że Twoja oryginalna lista pozostanie niezmieniona).

Zobaczmy.

sorted(nums)

zwroty

[-3, 1, 4, 5, 7, 8, 9, 14]

Patrząc numsponownie

nums

Widzimy oryginalną listę (niezmienioną i NIE posortowaną). sortednie zmienił oryginalnej listy

[1, 2, -3, 4, 8, 5, 7, 14]

Biorąc tę ​​samą numslistę i stosując na niej sortfunkcję, zmieni aktualną listę.

Zobaczmy.

Począwszy od naszej numslisty, aby upewnić się, treść jest nadal taka sama.

nums

[-3, 1, 4, 5, 7, 8, 9, 14]

nums.sort()

Teraz oryginalna lista liczb jest zmieniona i patrząc na liczby widzimy, że nasza oryginalna lista uległa zmianie i jest teraz posortowana.

nums
[-3, 1, 2, 4, 5, 7, 8, 14]

Dziękujemy za bardziej szczegółowe przedstawienie oryginału vs. kopii
— Brendan Metcalfe

0

Uwaga: Najprostsza różnica między sort () a sorted () to: sort () nie zwraca żadnej wartości, podczas gdy sorted () zwraca listę iterowalną.

sort () nie zwraca żadnej wartości.

Metoda sort () po prostu sortuje elementy danej listy w określonej kolejności - Rosnąco lub Malejąco bez zwracania żadnej wartości.

Składnia metody sort () to:

list.sort(key=..., reverse=...)

Alternatywnie można również użyć wbudowanej funkcji Pythona sorted () w tym samym celu. posortowana funkcja zwraca posortowaną listę

 list=sorted(list, key=..., reverse=...)
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.