В чем разница между `sorted (list)` vs `list.sort ()`?


194

list.sort()сортирует список и заменяет исходный список, а sorted(list)возвращает отсортированную копию списка без изменения исходного списка.

  • Когда один предпочтительнее другого?
  • Что является более эффективным? На сколько?
  • Можно ли вернуть список в несортированное состояние после list.sort()выполнения?

4
Остерегайтесь, если вы (случайно) вызываете sorted()строковый аргумент, но думаете, что это список, вы получаете результат списка, а не строку : sorted("abcd", reverse=True)дает ['d', 'c', 'b', 'a']не"dcba"
— smci

Ответы:


317

sorted()возвращает новый отсортированный список, оставляя исходный список без изменений. list.sort()сортирует список на месте , изменяет индексы списка и возвращает None(как и все операции на месте).

sorted()работает с любыми повторяемыми, а не только списками. Строки, кортежи, словари (вы получите ключи), генераторы и т. Д., Возвращая список, содержащий все отсортированные элементы.

  • Используйте, list.sort()если вы хотите изменить список, sorted()когда вы хотите, чтобы новый отсортированный объект вернулся. Используйте , sorted()если вы хотите , чтобы отсортировать то , что является итератор, а не список еще .

  • Для списков list.sort()это быстрее, чем sorted()потому, что не нужно создавать копию. Для любой другой повторяемости у вас нет выбора.

  • Нет, вы не можете восстановить исходные позиции. Как только вы позвонили, list.sort()первоначальный заказ исчез.


6
В общем, когда функция python возвращается None, это признак того, что операции выполнены на месте, поэтому, когда вы хотите напечатать, list.sort()она возвращает None.
— user1767754

45

В чем разница между sorted(list)против list.sort()?

  • list.sort мутирует список на месте и возвращает None
  • sorted принимает любую итерацию и возвращает новый список, отсортированный.

sorted эквивалентно этой реализации Python, но встроенная функция CPython должна выполняться заметно быстрее, как написано в 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

когда использовать какой?

  • использование list.sort если вы не хотите сохранять исходный порядок сортировки (таким образом, вы сможете повторно использовать список на месте в памяти.) И когда вы являетесь единственным владельцем списка (если список используется другим кодом, и вы мутировать его, вы можете вносить ошибки, где этот список используется.)
  • Используйте, sortedесли вы хотите сохранить исходный порядок сортировки или когда вы хотите создать новый список, которым владеет только ваш локальный код.

Можно ли получить исходные позиции списка после list.sort ()?

Нет - если вы не сделали копию самостоятельно, эта информация будет потеряна, потому что сортировка выполняется на месте.

«А что быстрее? И насколько быстрее?»

Чтобы проиллюстрировать недостатки создания нового списка, используйте модуль timeit, вот наши настройки:

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
"""

И вот наши результаты для списка случайным образом расположенных 10000 целых чисел, как мы можем видеть здесь, мы опровергли более старый миф о расходах на создание списка :

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]

После некоторой обратной связи я решил, что желателен другой тест с другими характеристиками. Здесь я предоставляю один и тот же случайно упорядоченный список длиной 100 000 для каждой итерации 1000 раз.

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

Я интерпретирую разницу этого более крупного сорта от копирования, упомянутого Мартийном, но она не доминирует в той точке, которая указана в более старом, более популярном ответе здесь, здесь увеличение времени составляет всего около 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]

Я также выполнил вышеупомянутое в намного меньшем виде и увидел, что новая sortedверсия копии все еще занимает примерно на 2% больше времени работы при длине порядка 1000.

Poke также запустил свой собственный код, вот код:

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))

Он нашел для сортировки длины 1000000 (выполненной 100 раз) аналогичный результат, но только с увеличением времени примерно на 5%, вот результат:

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

Вывод:

Список большого размера, сортируемый с sortedсозданием копии, вероятно, будет доминировать в различиях, но сама сортировка доминирует в операции, и организация вашего кода вокруг этих различий будет преждевременной оптимизацией. Я бы использовал, sortedкогда мне нужен новый отсортированный список данных, и я бы использовал, list.sortкогда мне нужно отсортировать список на месте, и пусть это определяет мое использование.


4
Генераторная установка хороша, но я бы не сделал вывод, что ты слишком быстро разрушил миф. Остается факт, что sorted()нужно выделить новый объект списка и скопировать ссылки; остальные пути кода идентичны. Посмотрите, сможете ли вы запустить те же тесты с большими списками. Сравните это только с созданием копий списков и посмотрите, сможете ли вы воспроизвести найденные различия и т. Д.
— Мартин Питерс

11

Основное отличие в том, что sorted(some_list)возвращает новоеlist :

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

и some_list.sort(), сортирует список на месте :

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

Обратите внимание, что, поскольку a.sort()ничего не возвращает, print a.sort()напечатает None.


Можно ли получить исходные позиции списка после list.sort ()?

Нет, потому что он изменяет исходный список.


1
print a.sort()не буду ничего печатать.
— Бурхан Халид

1
Он напечатает None, я уточню это.
— Кристиан

1

Функция .sort () сохраняет значение нового списка непосредственно в переменной списка; поэтому ответ на ваш третий вопрос будет НЕТ. Также, если вы сделаете это с помощью сортировки (список), вы можете использовать его, потому что он не хранится в переменной списка. Также иногда метод .sort () действует как функция или говорит, что принимает в нем аргументы.

Вы должны хранить значение sorted (list) в переменной явно.

Также для короткой обработки данных скорость не будет иметь никакого значения; но для длинных списков; Вы должны напрямую использовать метод .sort () для быстрой работы; но опять вы столкнетесь с необратимыми действиями.


Msgstr "Функция .sort () сохраняет значение нового списка прямо в переменной списка" А? Какой новый список? Там нет нового списка. list.sort()Метод сортирует список объектов на месте.
— PM 2Ring

Кроме того, что это должно означать? «Иногда метод .sort () действует как функция или говорит, что принимает в нем аргументы.»
— PM 2Ring

Под новым списком я подразумеваю измененный список, а .sort () просто сохраняет этот измененный список в той же самой переменной.
— Vicrobot,

Да, абсолютно иногда .sort()метод принимает аргумент и действует как функция. Также мы называем это методом, потому что это атрибут типа списка.
— Vicrobot

Если в моей концепции есть какая-то ошибка, то скажите мне, я поищу ее и улучшу свои концепции, и мой ответ тоже. Спасибо
— Vicrobot

1

Вот несколько простых примеров, чтобы увидеть разницу в действии:

Смотрите список номеров здесь:

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

При звонке sortedв этот список, sortedсделаю копию списка. (То есть ваш первоначальный список останется без изменений.)

Посмотрим.

sorted(nums)

возвращается

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

Глядя на numsснова

nums

Мы видим исходный список (без изменений и НЕ отсортированный.). sortedне изменил первоначальный список

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

Взяв тот же numsсписок и применив к нему sortфункцию, изменится фактический список.

Посмотрим.

Начнем с нашего numsсписка, чтобы убедиться, что содержание остается прежним.

nums

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

nums.sort()

Теперь оригинальный список чисел изменен, и, глядя на числа, мы видим, что наш исходный список изменился и теперь сортируется.

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

Спасибо, что показали оригинал против копии более подробно
— Брендан Меткалф

0

Примечание. Простейшая разница между sort () и sorted () заключается в следующем: sort () не возвращает никакого значения, а sorted () возвращает итеративный список.

sort () не возвращает никакого значения.

Метод sort () просто сортирует элементы данного списка в определенном порядке - по возрастанию или по убыванию без возврата какого-либо значения.

Синтаксис метода sort ():

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

Кроме того, вы также можете использовать встроенную функцию Python sorted () для той же цели. отсортированная функция возвращает отсортированный список

 list=sorted(list, key=..., reverse=...)
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.