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.