Chi phí của hàm len ()


Câu trả lời:


341

Đó là O (1) (thời gian không đổi, không phụ thuộc vào độ dài thực tế của phần tử - rất nhanh) trên mọi loại bạn đã đề cập, cộng với các setloại khác như array.array.


17
Cảm ơn câu trả lời hữu ích! Có bất kỳ loại bản địa nào mà đây không phải là trường hợp?
mvanveen

141

Gọi len () trên các loại dữ liệu đó là O (1) trong CPython , cách triển khai phổ biến nhất của ngôn ngữ Python. Đây là một liên kết đến một bảng cung cấp độ phức tạp thuật toán của nhiều hàm khác nhau trong CPython:

Trang Wiki của TimeComplexity Python


84

Tất cả những đối tượng theo dõi chiều dài của riêng họ. Thời gian để trích xuất độ dài là nhỏ (O (1) trong ký hiệu big-O) và chủ yếu bao gồm [mô tả thô, được viết bằng thuật ngữ Python, không phải thuật ngữ C]: tra cứu "len" trong từ điển và gửi nó đến Hàm build_in len sẽ tìm kiếm __len__phương thức của đối tượng và gọi rằng ... tất cả những gì nó phải làm làreturn self.length


3
Tôi nghĩ rằng đây là câu trả lời thích hợp nhất vì điều này cung cấp cái nhìn sâu sắc về các chi tiết thực hiện.
AK

Tại sao không lengthxuất hiện trong từ điển dir(list)?
ViFI

đây là những gì tôi đang tìm kiếm
Visakh Vijayan

@ViFI Vì đó chỉ là một ví dụ. Biến minh họa list.lenghtđược thực hiện trong C, không phải Python.
Cửu Long

73

Các phép đo dưới đây cung cấp bằng chứng len()là O (1) cho các cấu trúc dữ liệu được sử dụng.

Một lưu ý liên quan đến timeit: Khi -scờ được sử dụng và hai chuỗi được chuyển đếntimeit chuỗi đầu tiên chỉ được thực hiện một lần và không được tính thời gian.

Danh sách:

$ python -m timeit -s "l = range(10);" "len(l)"
10000000 loops, best of 3: 0.0677 usec per loop

$ python -m timeit -s "l = range(1000000);" "len(l)"
10000000 loops, best of 3: 0.0688 usec per loop

Bộ dữ liệu:

$ python -m timeit -s "t = (1,)*10;" "len(t)"
10000000 loops, best of 3: 0.0712 usec per loop

$ python -m timeit -s "t = (1,)*1000000;" "len(t)"
10000000 loops, best of 3: 0.0699 usec per loop

Chuỗi:

$ python -m timeit -s "s = '1'*10;" "len(s)"
10000000 loops, best of 3: 0.0713 usec per loop

$ python -m timeit -s "s = '1'*1000000;" "len(s)"
10000000 loops, best of 3: 0.0686 usec per loop

Từ điển (hiểu từ điển có sẵn trong 2.7+):

$ python -mtimeit -s"d = {i:j for i,j in enumerate(range(10))};" "len(d)"
10000000 loops, best of 3: 0.0711 usec per loop

$ python -mtimeit -s"d = {i:j for i,j in enumerate(range(1000000))};" "len(d)"
10000000 loops, best of 3: 0.0727 usec per loop

Mảng:

$ python -mtimeit -s"import array;a=array.array('i',range(10));" "len(a)"
10000000 loops, best of 3: 0.0682 usec per loop

$ python -mtimeit -s"import array;a=array.array('i',range(1000000));" "len(a)"
10000000 loops, best of 3: 0.0753 usec per loop

Đặt (hiểu toàn bộ có sẵn trong 2.7+):

$ python -mtimeit -s"s = {i for i in range(10)};" "len(s)"
10000000 loops, best of 3: 0.0754 usec per loop

$ python -mtimeit -s"s = {i for i in range(1000000)};" "len(s)"
10000000 loops, best of 3: 0.0713 usec per loop

Deque:

$ python -mtimeit -s"from collections import deque;d=deque(range(10));" "len(d)"
100000000 loops, best of 3: 0.0163 usec per loop

$ python -mtimeit -s"from collections import deque;d=deque(range(1000000));" "len(d)"
100000000 loops, best of 3: 0.0163 usec per loop

1
Đây không phải là một điểm chuẩn tốt cho dù nó cho thấy những gì chúng ta đã biết. Điều này là do phạm vi (10) và phạm vi (1000000) không được coi là O (1).
Không biết

3
Đây là câu trả lời tốt nhất. Bạn chỉ nên thêm một kết luận trong trường hợp ai đó không nhận ra thời gian liên tục.
santiagobasulto

4
Cảm ơn các bình luận. Tôi đã thêm một lưu ý về độ phức tạp O (1) len()và cũng đã sửa các phép đo để sử dụng -scờ đúng cách .
Mechanical_meat

Điều quan trọng cần lưu ý là việc lưu độ dài vào một biến có thể tiết kiệm đáng kể thời gian tính toán: python -m timeit -s "l = range(10000);" "len(l); len(l); len(l)"223 nsec mỗi vòng python -m timeit -s "l = range(100);" "len(l)"66,2 nsec mỗi vòng
Radostin Stoyanov

16

len là một O (1) vì trong RAM của bạn, các danh sách được lưu dưới dạng bảng (chuỗi các địa chỉ liền kề). Để biết khi nào bảng dừng máy tính cần hai thứ: chiều dài và điểm bắt đầu. Đó là lý do tại sao len () là O (1), máy tính lưu trữ giá trị, vì vậy nó chỉ cần tra cứu nó.


3

Tôi đã nghĩ về len () trong Python phụ thuộc vào kích thước của danh sách, vì vậy tôi luôn lưu trữ độ dài trong một biến nếu tôi sử dụng nhiều lần. Nhưng hôm nay trong khi gỡ lỗi, tôi nhận thấy thuộc tính __len__ trong đối tượng danh sách, vì vậy len () phải chỉ tìm nạp nó, điều này làm cho độ phức tạp O (1). Vì vậy, tôi chỉ loay hoay nếu ai đó đã hỏi nó và xem qua bài đăng này.


Nhưng __len__là một chức năng, không phải là một biến đại diện cho chiều dài của danh sách.
Cửu Long

@Kowalski có len là một chức năng nhưng tất cả những gì nó làm là, nó sẽ trả về self.length
AYUSH SENAPATI

Nhưng bài viết của bạn không nói gì về điều đó. Ngoài ra làm thế nào để bạn biết rằng list.__len__chức năng chạy trong thời gian liên tục? Nó không, nhưng không chỉ vì nó là một chức năng. Bởi vì nó thực hiện như vậy.
Cửu Long
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.