Sự khác biệt giữa `sort (list)` vs `list.sort ()` là gì?


194

list.sort()sắp xếp danh sách và thay thế danh sách ban đầu, trong khi sorted(list)trả về một bản sao được sắp xếp của danh sách mà không thay đổi danh sách ban đầu.

  • Khi nào một cái được ưa thích hơn cái kia?
  • Cái nào hiệu quả hơn? Bằng bao nhiêu?
  • Một danh sách có thể được hoàn nguyên về trạng thái chưa sắp xếp sau khi list.sort()đã được thực hiện không?

4
Coi chừng nếu bạn (vô tình) gọi sorted()một đối số chuỗi nhưng nghĩ đó là danh sách, bạn nhận được kết quả danh sách, không phải là chuỗi : không sorted("abcd", reverse=True)cho['d', 'c', 'b', 'a']"dcba"
smci

Câu trả lời:


316

sorted()trả về một danh sách được sắp xếp mới , khiến danh sách ban đầu không bị ảnh hưởng. list.sort()sắp xếp danh sách tại chỗ , thay đổi các chỉ mục danh sách và trả về None(giống như tất cả các hoạt động tại chỗ).

sorted()hoạt động trên bất kỳ danh sách lặp, không chỉ danh sách. Chuỗi, bộ dữ liệu, từ điển (bạn sẽ nhận được các phím), trình tạo, v.v., trả về một danh sách chứa tất cả các thành phần, được sắp xếp.

  • Sử dụng list.sort()khi bạn muốn thay đổi danh sách, sorted()khi bạn muốn một đối tượng được sắp xếp mới trở lại. Sử dụng sorted()khi bạn muốn sắp xếp cái gì đó là một iterable, không phải là một danh sách được nêu ra .

  • Đối với danh sách, list.sort()nhanh hơn sorted()vì không phải tạo bản sao. Đối với bất kỳ lặp đi lặp lại khác, bạn không có sự lựa chọn.

  • Không, bạn không thể lấy lại các vị trí ban đầu. Một khi bạn gọi list.sort()thứ tự ban đầu đã biến mất.


6
Nói chung, khi một hàm python trả về None, đó là một dấu hiệu, rằng các thao tác được thực hiện tại chỗ, đó là lý do tại sao, khi bạn muốn in, list.sort()nó sẽ trả về Không.
dùng1767754

45

Sự khác biệt giữa sorted(list)vs là list.sort()gì?

  • list.sort làm thay đổi danh sách tại chỗ và trả lại None
  • sorted mất bất kỳ lần lặp nào và trả về một danh sách mới, được sắp xếp.

sorted tương đương với triển khai Python này, nhưng hàm dựng sẵn CPython sẽ chạy nhanh hơn đáng kể vì nó được viết bằng 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

Khi nào sử dụng?

  • Sử dụng list.sortkhi bạn không muốn giữ lại thứ tự sắp xếp ban đầu (Do đó bạn sẽ có thể sử dụng lại danh sách tại chỗ trong bộ nhớ.) Và khi bạn là chủ sở hữu duy nhất của danh sách (nếu danh sách được chia sẻ bởi mã khác và bạn làm thay đổi nó, bạn có thể giới thiệu các lỗi trong đó danh sách đó được sử dụng.)
  • Sử dụng sortedkhi bạn muốn giữ lại thứ tự sắp xếp ban đầu hoặc khi bạn muốn tạo một danh sách mới mà chỉ mã địa phương của bạn sở hữu.

Vị trí ban đầu của danh sách có thể được truy xuất sau list.sort () không?

Không - trừ khi bạn tự tạo một bản sao, thông tin đó sẽ bị mất vì việc sắp xếp được thực hiện tại chỗ.

"Và cái nào nhanh hơn? Và nhanh hơn bao nhiêu?"

Để minh họa hình phạt của việc tạo danh sách mới, hãy sử dụng mô-đun thời gian, đây là thiết lập của chúng tôi:

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

Và đây là kết quả của chúng tôi cho một danh sách 10000 số nguyên được sắp xếp ngẫu nhiên, như chúng ta có thể thấy ở đây, chúng tôi đã bác bỏ một huyền thoại chi phí tạo danh sách cũ hơn :

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]

Con trăn 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]

Sau một số phản hồi, tôi quyết định một thử nghiệm khác sẽ được mong muốn với các đặc điểm khác nhau. Ở đây tôi cung cấp cùng một danh sách được sắp xếp ngẫu nhiên 100.000 độ dài cho mỗi lần lặp 1.000 lần.

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

Tôi giải thích sự khác biệt của loại lớn hơn này đến từ việc sao chép được đề cập bởi Martijn, nhưng nó không chi phối đến điểm được nêu trong câu trả lời phổ biến cũ hơn ở đây, ở đây mức tăng thời gian chỉ khoảng 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]

Tôi cũng đã chạy ở trên với một loại nhỏ hơn nhiều và thấy rằng sortedphiên bản sao chép mới vẫn mất thời gian chạy lâu hơn khoảng 2% với độ dài 1000.

Poke cũng chạy mã của riêng mình, đây là mã:

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

Ông đã tìm thấy loại 1000000 chiều dài, (chạy 100 lần) một kết quả tương tự, nhưng chỉ tăng khoảng 5% về thời gian, đây là đầu ra:

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

Phần kết luận:

Một danh sách có kích thước lớn được sắp xếp với sortedviệc tạo một bản sao có thể sẽ chi phối sự khác biệt, nhưng chính việc sắp xếp đó chi phối hoạt động và tổ chức mã của bạn xung quanh những khác biệt này sẽ là tối ưu hóa sớm. Tôi sẽ sử dụng sortedkhi tôi cần một danh sách dữ liệu được sắp xếp mới và tôi sẽ sử dụng list.sortkhi tôi cần sắp xếp danh sách tại chỗ và để điều đó xác định việc sử dụng của tôi.


4
Thiết lập trình tạo là tốt, nhưng tôi sẽ không rút ra kết luận rằng bạn đã nhận được một huyền thoại quá nhanh. Thực tế vẫn sorted()phải phân bổ một đối tượng danh sách mới và sao chép các tài liệu tham khảo; phần còn lại của các đường dẫn mã là giống hệt nhau. Xem nếu bạn có thể chạy các bài kiểm tra tương tự với danh sách lớn hơn. So sánh nó với việc chỉ tạo các bản sao của danh sách và xem liệu bạn có thể sao chép sự khác biệt mà bạn đã tìm thấy hay không, v.v.
Martijn Pieters

11

Sự khác biệt chính là sorted(some_list)trả về một cái mớilist :

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

some_list.sort(), sắp xếp danh sách tại chỗ :

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

Lưu ý rằng vì a.sort()không trả lại bất cứ điều gì, print a.sort()sẽ in None.


Danh sách các vị trí ban đầu có thể được truy xuất sau list.sort () không?

Không, bởi vì nó sửa đổi danh sách ban đầu.


1
print a.sort()sẽ không in bất cứ điều gì.
Burhan Khalid

1
Nó sẽ in None, tôi sẽ làm rõ điều đó.
Christian

1

Hàm .sort () lưu trữ giá trị của danh sách mới trực tiếp trong biến danh sách; vì vậy câu trả lời cho câu hỏi thứ ba của bạn sẽ là KHÔNG. Ngoài ra nếu bạn làm điều này bằng cách sử dụng sort (danh sách), thì bạn có thể sử dụng nó vì nó không được lưu trong biến danh sách. Ngoài ra đôi khi phương thức .sort () đóng vai trò là hàm hoặc nói rằng nó lấy các đối số trong nó.

Bạn phải lưu trữ giá trị của sắp xếp (danh sách) trong một biến rõ ràng.

Ngoài ra đối với xử lý dữ liệu ngắn, tốc độ sẽ không có sự khác biệt; nhưng cho danh sách dài; bạn nên trực tiếp sử dụng phương thức .sort () để làm việc nhanh; nhưng một lần nữa bạn sẽ phải đối mặt với những hành động không thể đảo ngược.


"Hàm .sort () lưu trữ giá trị của danh sách mới trực tiếp trong biến danh sách" Huh? Danh sách mới nào? Không có danh sách mới. Các list.sort()phương pháp sắp xếp các đối tượng danh sách tại chỗ.
PM 2Ring

Ngoài ra, điều này có nghĩa là gì? "đôi khi phương thức .sort () đóng vai trò là hàm hoặc nói rằng nó lấy các đối số trong nó."
PM 2Ring

Ý nghĩa của danh sách mới là danh sách đã sửa đổi và .sort () chỉ lưu trữ danh sách đã sửa đổi đó vào cùng một biến.
Vicrobot

Có, hoàn toàn đôi khi .sort()phương thức lấy đối số và đóng vai trò là hàm. Ngoài ra chúng tôi gọi nó là phương thức vì nó là một thuộc tính của kiểu dữ liệu danh sách.
Vicrobot

Nếu có một số lỗi trong khái niệm của tôi thì hãy nói cho tôi biết, tôi sẽ tìm nó và sẽ cải thiện các khái niệm của tôi, và câu trả lời của tôi cũng vậy. Cảm ơn
Vicrobot

1

Dưới đây là một vài ví dụ đơn giản để thấy sự khác biệt trong hành động:

Xem danh sách các số tại đây:

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

Khi gọi sortedvào danh sách này, sortedsẽ tạo một bản sao của danh sách. (Có nghĩa là danh sách ban đầu của bạn sẽ không thay đổi.)

Hãy xem nào.

sorted(nums)

trả lại

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

Nhìn numslại

nums

Chúng tôi thấy danh sách ban đầu (không thay đổi và KHÔNG được sắp xếp.). sortedkhông thay đổi danh sách ban đầu

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

Lấy cùng một numsdanh sách và áp dụng sortchức năng trên nó, sẽ thay đổi danh sách thực tế.

Hãy xem nào.

Bắt đầu với numsdanh sách của chúng tôi để đảm bảo, nội dung vẫn giống nhau.

nums

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

nums.sort()

Bây giờ danh sách số gốc đã được thay đổi và nhìn vào số chúng ta thấy danh sách gốc của chúng ta đã thay đổi và hiện đã được sắp xếp.

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

Cảm ơn bạn đã hiển thị bản gốc so với bản sao sâu hơn
Brendan Metcalfe

0

Lưu ý: Sự khác biệt đơn giản nhất giữa sort () và sort () là: sort () không trả về bất kỳ giá trị nào trong khi, sort () trả về một danh sách lặp.

sort () không trả về bất kỳ giá trị nào.

Phương thức sort () chỉ sắp xếp các phần tử của một danh sách nhất định theo một thứ tự cụ thể - Tăng dần hoặc Giảm dần mà không trả về bất kỳ giá trị nào.

Cú pháp của phương thức sort () là:

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

Ngoài ra, bạn cũng có thể sử dụng hàm dựng sẵn của Python được sắp xếp () cho cùng một mục đích. chức năng sắp xếp trả về danh sách sắp xếp

 list=sorted(list, key=..., reverse=...)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.