Bộ Python vs Danh sách


187

Trong Python, cấu trúc dữ liệu nào hiệu quả / nhanh hơn? Giả sử rằng thứ tự đó không quan trọng đối với tôi và dù sao tôi cũng sẽ kiểm tra các bản sao, liệu Python có chậm hơn danh sách Python không?

Câu trả lời:


230

Nó phụ thuộc vào những gì bạn đang có ý định làm với nó.

Các bộ nhanh hơn đáng kể khi xác định xem một đối tượng có trong tập hợp không (như trong x in s ) hay không, nhưng chậm hơn các danh sách khi nói về việc lặp lại nội dung của chúng.

Bạn có thể sử dụng mô-đun thời gian để xem cái nào nhanh hơn cho tình huống của bạn.


4
Đối với quan điểm của bạn: "Bộ nhanh hơn đáng kể", việc triển khai cơ bản làm cho nó nhanh hơn là gì?
trao đổi quá mức

Các ngôn ngữ kịch bản muốn ẩn các triển khai cơ bản, nhưng sự đơn giản rõ ràng này không phải lúc nào cũng tốt, bạn cần một số nhận thức về 'cấu trúc dữ liệu' khi bạn thiết kế một phần mềm.
Barshe Roussy

4
Đặt không chậm hơn đáng kể so với danh sách trong khi lặp.
omerfarukdogan

38
Bộ và danh sách đều có vòng lặp thời gian tuyến tính. Để nói rằng một cái "chậm" hơn cái kia là sai lầm và đã gây nhầm lẫn cho các lập trình viên mới đọc câu trả lời này.
thói quen

@habnabit nếu bạn đang nói rằng cả hai đều có vòng lặp thời gian tuyến tính. Điều này có nghĩa là họ có cùng thời gian lặp lại? Sự khác biệt sau đó là gì?
Mohammed Noureldin

152

Danh sách nhanh hơn một chút so với các tập hợp khi bạn chỉ muốn lặp lại các giá trị.

Tuy nhiên, các bộ nhanh hơn đáng kể so với danh sách nếu bạn muốn kiểm tra xem một mục có được chứa trong đó không. Chúng chỉ có thể chứa các mặt hàng độc đáo mặc dù.

Hóa ra các bộ dữ liệu thực hiện theo cách gần như chính xác như các danh sách, ngoại trừ tính bất biến của chúng.

Lặp đi lặp lại

>>> def iter_test(iterable):
...     for i in iterable:
...         pass
...
>>> from timeit import timeit
>>> timeit(
...     "iter_test(iterable)",
...     setup="from __main__ import iter_test; iterable = set(range(10000))",
...     number=100000)
12.666952133178711
>>> timeit(
...     "iter_test(iterable)",
...     setup="from __main__ import iter_test; iterable = list(range(10000))",
...     number=100000)
9.917098999023438
>>> timeit(
...     "iter_test(iterable)",
...     setup="from __main__ import iter_test; iterable = tuple(range(10000))",
...     number=100000)
9.865639209747314

Xác định nếu một đối tượng có mặt

>>> def in_test(iterable):
...     for i in range(1000):
...         if i in iterable:
...             pass
...
>>> from timeit import timeit
>>> timeit(
...     "in_test(iterable)",
...     setup="from __main__ import in_test; iterable = set(range(1000))",
...     number=10000)
0.5591847896575928
>>> timeit(
...     "in_test(iterable)",
...     setup="from __main__ import in_test; iterable = list(range(1000))",
...     number=10000)
50.18339991569519
>>> timeit(
...     "in_test(iterable)",
...     setup="from __main__ import in_test; iterable = tuple(range(1000))",
...     number=10000)
51.597304821014404

6
Tôi đã tìm thấy rằng (Bộ khởi tạo -> 5.5300979614257812) (Danh sách khởi tạo -> 1.8846848011016846) (Khởi tạo tuple -> 1.8730108737945557) Các mục có kích thước 10.000 trên lõi i5 lõi tứ của tôi với RAM 12GB. Điều này cũng nên được xem xét.
ThePracticalOne

4
Tôi đã cập nhật mã để loại bỏ việc tạo đối tượng bây giờ. Giai đoạn thiết lập các vòng lặp timeit chỉ được gọi một lần ( docs.python.org/2/l Library / timeit.html # timeit.Timer.timeit ).
Ellis Percival

7

Danh sách hiệu suất:

>>> import timeit
>>> timeit.timeit(stmt='10**6 in a', setup='a = range(10**6)', number=100000)
0.008128150348026608

Đặt hiệu suất:

>>> timeit.timeit(stmt='10**6 in a', setup='a = set(range(10**6))', number=100000)
0.005674857488571661

Bạn có thể muốn xem xét Tuples vì chúng giống với danh sách nhưng không thể sửa đổi. Chúng chiếm ít bộ nhớ hơn và truy cập nhanh hơn. Chúng không linh hoạt nhưng hiệu quả hơn danh sách. Sử dụng bình thường của họ là để phục vụ như các khóa từ điển.

Các bộ cũng là cấu trúc trình tự nhưng có hai điểm khác biệt từ danh sách và bộ dữ liệu. Mặc dù các tập hợp có một thứ tự, thứ tự đó là tùy ý và không thuộc quyền kiểm soát của lập trình viên. Sự khác biệt thứ hai là các yếu tố trong một bộ phải là duy nhất.

settheo định nghĩa. [ trăn | wiki ].

>>> x = set([1, 1, 2, 2, 3, 3])
>>> x
{1, 2, 3}

4
Trước hết, bạn nên cập nhật lên setliên kết loại tích hợp ( docs.python.org/2/l Library / stdtypes.html # set ) chứ không phải setsthư viện không dùng nữa . Thứ hai, "Bộ cũng là cấu trúc trình tự", đọc phần sau từ liên kết loại tích hợp: "Là bộ sưu tập không có thứ tự, các bộ không ghi vị trí phần tử hoặc thứ tự chèn. Theo đó, các bộ không hỗ trợ lập chỉ mục, cắt hoặc khác hành vi giống như trình tự. "
Seaux

7
rangekhông phải là list. rangelà một lớp học đặc biệt với __contains__phương pháp ma thuật tùy chỉnh .
Ryne Wang

@RyneWang điều này đúng, nhưng chỉ với Python3. Trong phạm vi Python2 trả về một danh sách bình thường (đó là lý do tại sao tồn tại những thứ khủng khiếp như xrange)
Manoel Vilela

7

Setchiến thắng do gần như ngay lập tức 'chứa' séc: https://en.wikipedia.org/wiki/Hash_table

Danh sách thực hiện: thường là một mảng, mức độ thấp gần với kim loại, tốt cho việc lặp lại và truy cập ngẫu nhiên theo chỉ số phần tử.

Đặt triển khai: https://en.wikipedia.org/wiki/Hash_table , nó không lặp lại trong danh sách, nhưng tìm phần tử bằng cách tính băm từ khóa, vì vậy nó phụ thuộc vào bản chất của các phần tử chính và hàm băm chức năng. Tương tự như những gì được sử dụng cho dict. Tôi nghi ngờ listcó thể nhanh hơn nếu bạn có rất ít yếu tố (<5), yếu tố càng lớn thì khả năng setthực hiện đối với kiểm tra có chứa càng tốt . Nó cũng nhanh chóng để thêm và loại bỏ yếu tố. Cũng luôn luôn nhớ rằng xây dựng một bộ có chi phí!

LƯU Ý : Nếu listđã được sắp xếp, việc tìm kiếm listcó thể khá nhanh, nhưng đối với các trường hợp thông thường, a setsẽ nhanh hơn và đơn giản hơn để chứa séc.


8
Gần kim loại? Điều đó có nghĩa gì trong bối cảnh của Python? Làm thế nào là một danh sách gần với kim loại hơn một bộ?
roganjosh

@roganjosh, python vẫn chạy trên máy và một số triển khai như danh sách 'mảng' gần với phần cứng hơn: stackoverflow.com/questions/176011/ , nhưng nó luôn phụ thuộc vào những gì bạn muốn đạt được, nó là tốt để biết một chút về các triển khai, không chỉ là trừu tượng.
Barshe Roussy

2

tl; dr

Cấu trúc dữ liệu (DS) rất quan trọng vì chúng được sử dụng để thực hiện các thao tác trên dữ liệu về cơ bản ngụ ý: lấy một số đầu vào , xử lý nótrả lại đầu ra .

Một số cấu trúc dữ liệu hữu ích hơn những cấu trúc khác trong một số trường hợp cụ thể. Do đó, thật không công bằng khi hỏi (DS) nào hiệu quả / nhanh hơn. Nó giống như hỏi công cụ nào hiệu quả hơn giữa dao và nĩa. Ý tôi là tất cả phụ thuộc vào tình hình.

Danh sách

Một danh sách là chuỗi có thể thay đổi , thường được sử dụng để lưu trữ các bộ sưu tập các mặt hàng đồng nhất .

Bộ

Một đối tượng được thiết lập là một bộ sưu tập các đối tượng có thể băm riêng biệt . Nó thường được sử dụng để kiểm tra tư cách thành viên, loại bỏ các bản sao khỏi chuỗi và tính toán các phép toán như giao điểm, liên kết, chênh lệch và chênh lệch đối xứng.

Sử dụng

Từ một số câu trả lời, rõ ràng một danh sách khá nhanh hơn một tập hợp khi lặp qua các giá trị. Mặt khác, một bộ nhanh hơn một danh sách khi kiểm tra xem một mục có được chứa trong đó không. Do đó, điều duy nhất bạn có thể nói là một danh sách tốt hơn một bộ cho một số hoạt động cụ thể và ngược lại.


2

Tôi đã quan tâm đến kết quả khi kiểm tra, với CPython, nếu một giá trị là một trong số ít chữ. setthắng bằng Python 3 vs tuple, listor:

from timeit import timeit

def in_test1():
  for i in range(1000):
    if i in (314, 628):
      pass

def in_test2():
  for i in range(1000):
    if i in [314, 628]:
      pass

def in_test3():
  for i in range(1000):
    if i in {314, 628}:
      pass

def in_test4():
  for i in range(1000):
    if i == 314 or i == 628:
      pass

print("tuple")
print(timeit("in_test1()", setup="from __main__ import in_test1", number=100000))
print("list")
print(timeit("in_test2()", setup="from __main__ import in_test2", number=100000))
print("set")
print(timeit("in_test3()", setup="from __main__ import in_test3", number=100000))
print("or")
print(timeit("in_test4()", setup="from __main__ import in_test4", number=100000))

Đầu ra:

tuple
4.735646052286029
list
4.7308746771886945
set
3.5755991376936436
or
4.687681658193469

Trong 3 đến 5 chữ, setvẫn thắng với tỷ lệ chênh lệch cao và ortrở thành chậm nhất.

Trong Python 2, setluôn là chậm nhất. orlà nhanh nhất cho 2-3 literals, và tuplelistnhanh hơn với 4 hoặc nhiều chữ. Tôi không thể phân biệt tốc độ của tuplevs list.

Khi các giá trị cần kiểm tra được lưu trong bộ biến toàn cục ngoài hàm, thay vì tạo ra chữ trong vòng lặp, sẽ setgiành chiến thắng mọi lúc, ngay cả trong Python 2.

Những kết quả này áp dụng cho CPython 64 bit trên Core i7.


0

Tôi muốn giới thiệu Cài đặt thực hiện trong đó trường hợp sử dụng là giới hạn đối với tham chiếu hoặc tìm kiếm sự tồn tại và triển khai Tuple trong đó trường hợp sử dụng yêu cầu bạn thực hiện phép lặp. Một danh sách là một triển khai cấp thấp và đòi hỏi chi phí bộ nhớ đáng kể.


1
Thật vậy, sự phân biệt thích hợp giữa thời điểm sử dụng Bộ và khi nào sử dụng Tuple thực sự rất quan trọng. Tôi sẽ không lo lắng về các chi phí bộ nhớ, dấu chân liên quan trừ khi tôi đang viết kịch bản API cấp thấp hơn.

0
from datetime import datetime
listA = range(10000000)
setA = set(listA)
tupA = tuple(listA)
#Source Code

def calc(data, type):
start = datetime.now()
if data in type:
print ""
end = datetime.now()
print end-start

calc(9999, listA)
calc(9999, tupA)
calc(9999, setA)

Đầu ra sau khi so sánh 10 lần lặp cho cả 3: So sánh


0

Các bộ nhanh hơn, điều chỉnh bạn nhận được nhiều chức năng hơn với các bộ, chẳng hạn như giả sử bạn có hai bộ:

set1 = {"Harry Potter", "James Bond", "Iron Man"}
set2 = {"Captain America", "Black Widow", "Hulk", "Harry Potter", "James Bond"}

Chúng ta có thể dễ dàng tham gia hai bộ:

set3 = set1.union(set2)

Tìm hiểu những gì phổ biến trong cả hai:

set3 = set1.intersection(set2)

Tìm hiểu những gì là khác nhau trong cả hai:

set3 = set1.difference(set2)

Và nhiều hơn nữa! Chỉ cần thử chúng ra, chúng rất vui! Ngoài ra, nếu bạn phải làm việc với các giá trị khác nhau trong 2 danh sách hoặc các giá trị chung trong 2 danh sách, tôi thích chuyển đổi danh sách của bạn thành các bộ và nhiều lập trình viên thực hiện theo cách đó. Hy vọng nó sẽ giúp bạn :-)

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.