Який ідіоматичний синтаксис для подання до короткого списку пітонів?
Зазвичай ви не хочете, щоб повторно додавати до списку в Python.
Якщо він короткий , і ти це не робиш багато ... тоді добре.
list.insert
list.insert
Можна використовувати таким чином.
list.insert(0, x)
Але це неефективно, тому що в Python a list
- це масив покажчиків, і Python тепер повинен взяти кожен покажчик у списку і перемістити його вниз, щоб вставити вказівник на ваш об'єкт у першому слоті, так що це дійсно лише ефективно для досить коротких списків, як ви просите.
Ось фрагмент із джерела CPython, де це реалізовано - і як ви бачите, ми починаємо в кінці масиву і переміщуємо все вниз по одному для кожної вставки:
for (i = n; --i >= where; )
items[i+1] = items[i];
Якщо ви хочете, щоб контейнер / список був ефективним для попередніх елементів, ви хочете пов'язаний список. У Python є подвійно пов'язаний список, який можна вставити на початку та в кінці швидко - це називається a deque
.
deque.appendleft
A collections.deque
має багато методів списку. list.sort
є винятком, що робить, deque
безумовно, не зовсім Лісков заміною list
.
>>> set(dir(list)) - set(dir(deque))
{'sort'}
deque
Також має appendleft
метод (а також popleft
). Це deque
двобічна черга і подвійно пов'язаний список - незалежно від тривалості, завжди потрібно однакову кількість часу, щоб щось попередньо підготувати. У великих O позначеннях O (1) проти часу O (n) для списків. Ось використання:
>>> import collections
>>> d = collections.deque('1234')
>>> d
deque(['1', '2', '3', '4'])
>>> d.appendleft('0')
>>> d
deque(['0', '1', '2', '3', '4'])
deque.extendleft
Також актуальним є extendleft
метод деке, який ітераційно передбачає:
>>> from collections import deque
>>> d2 = deque('def')
>>> d2.extendleft('cba')
>>> d2
deque(['a', 'b', 'c', 'd', 'e', 'f'])
Зауважте, що кожен елемент буде заздалегідь пошкоджений один за одним, тим самим ефективно змінюючи їх порядок.
Продуктивність list
протиdeque
Спочатку ми налаштовуємо з деякою ітераційною попередньою формою:
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
та продуктивність:
>>> 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's, extendleft
ви, мабуть, отримаєте найкращі показники таким чином.