Cú pháp thành ngữ để chuẩn bị cho một danh sách python ngắn là gì?
Bạn thường không muốn lặp đi lặp lại một danh sách trong Python.
Nếu nó ngắn và bạn không làm việc đó nhiều ... thì ok.
list.insert
Có list.insert
thể được sử dụng theo cách này.
list.insert(0, x)
Nhưng điều này là không hiệu quả, bởi vì trong Python, a list
là một mảng các con trỏ và Python bây giờ phải lấy mọi con trỏ trong danh sách và di chuyển nó xuống một để chèn con trỏ vào đối tượng của bạn trong khe đầu tiên, vì vậy điều này thực sự chỉ hiệu quả cho danh sách khá ngắn, như bạn yêu cầu.
Đây là một đoạn trích từ nguồn CPython , nơi điều này được triển khai - và như bạn có thể thấy, chúng tôi bắt đầu ở cuối mảng và di chuyển mọi thứ xuống một cho mỗi lần chèn:
for (i = n; --i >= where; )
items[i+1] = items[i];
Nếu bạn muốn một thùng chứa / danh sách hiệu quả trong việc chuẩn bị các yếu tố, bạn muốn có một danh sách được liên kết. Python có một danh sách liên kết đôi, có thể chèn vào đầu và cuối một cách nhanh chóng - nó được gọi là a deque
.
deque.appendleft
A collections.deque
có nhiều phương pháp của một danh sách. list.sort
là một ngoại lệ, làm cho deque
dứt khoát không hoàn toàn thay thế Liskov cho list
.
>>> set(dir(list)) - set(dir(deque))
{'sort'}
Các deque
còn có một appendleft
phương pháp (cũng như popleft
). Đây deque
là một hàng đợi hai đầu và một danh sách liên kết đôi - bất kể độ dài, nó luôn mất cùng một khoảng thời gian để trả trước một cái gì đó. Trong ký hiệu O lớn, O (1) so với thời gian O (n) cho danh sách. Đây là cách sử dụng:
>>> import collections
>>> d = collections.deque('1234')
>>> d
deque(['1', '2', '3', '4'])
>>> d.appendleft('0')
>>> d
deque(['0', '1', '2', '3', '4'])
deque.extendleft
Cũng có liên quan là extendleft
phương pháp của deque , mà lặp đi lặp lại:
>>> from collections import deque
>>> d2 = deque('def')
>>> d2.extendleft('cba')
>>> d2
deque(['a', 'b', 'c', 'd', 'e', 'f'])
Lưu ý rằng mỗi phần tử sẽ được đặt trước một phần tử, do đó đảo ngược hiệu quả thứ tự của chúng.
Hiệu suất list
so vớideque
Đầu tiên chúng tôi thiết lập với một số lần lặp lại:
import timeit
from collections import deque
def list_insert_0():
l = []
for i in range(20):
l.insert(0, i)
def list_slice_insert():
l = []
for i in range(20):
l[:0] = [i] # semantically same as list.insert(0, i)
def list_add():
l = []
for i in range(20):
l = [i] + l # caveat: new list each time
def deque_appendleft():
d = deque()
for i in range(20):
d.appendleft(i) # semantically same as list.insert(0, i)
def deque_extendleft():
d = deque()
d.extendleft(range(20)) # semantically same as deque_appendleft above
và trình diễn:
>>> min(timeit.repeat(list_insert_0))
2.8267281929729506
>>> min(timeit.repeat(list_slice_insert))
2.5210217320127413
>>> min(timeit.repeat(list_add))
2.0641671380144544
>>> min(timeit.repeat(deque_appendleft))
1.5863927800091915
>>> min(timeit.repeat(deque_extendleft))
0.5352169770048931
Deque nhanh hơn nhiều. Khi các danh sách dài hơn, tôi sẽ mong đợi một deque sẽ thực hiện tốt hơn nữa. Nếu bạn có thể sử dụng deque, extendleft
có lẽ bạn sẽ có được hiệu suất tốt nhất theo cách đó.