Jaka jest idiomatyczna składnia dla poprzedzania krótkiej listy python?
Zwykle nie chcesz powtarzalnie dodawać do listy w Pythonie.
Jeśli jest krótki i nie robisz tego dużo ... to dobrze.
list.insert
list.insert
Mogą być wykorzystane w ten sposób.
list.insert(0, x)
Jest to jednak nieefektywne, ponieważ w Pythonie a list
to tablica wskaźników, a Python musi teraz pobrać każdy wskaźnik z listy i przesunąć go o jeden w dół, aby wstawić wskaźnik do obiektu w pierwszym gnieździe, więc jest to naprawdę skuteczne dla raczej krótkich list, jak pytasz.
Oto fragment kodu źródłowego CPython, w którym jest on zaimplementowany - i jak widać, zaczynamy od końca tablicy i przesuwamy wszystko o jeden w dół dla każdego wstawienia:
for (i = n; --i >= where; )
items[i+1] = items[i];
Jeśli potrzebujesz kontenera / listy, która jest wydajna w dodawaniu elementów, potrzebujesz listy połączonej. Python ma podwójnie połączoną listę, którą można szybko wstawiać na początku i na końcu - nazywa się to deque
.
deque.appendleft
collections.deque
Ma wiele sposobów na liście. list.sort
jest wyjątkiem, który deque
definitywnie nie zastępuje Liskova list
.
>>> set(dir(list)) - set(dir(deque))
{'sort'}
Ma deque
również appendleft
metodę (jak również popleft
). deque
Jest dwukrotnie zakończył kolejka i podwójnie związany list - bez względu na długość, to zawsze ma taką samą ilość czasu, aby preprend coś. W dużej notacji O, O (1) a czas O (n) dla list. Oto użycie:
>>> import collections
>>> d = collections.deque('1234')
>>> d
deque(['1', '2', '3', '4'])
>>> d.appendleft('0')
>>> d
deque(['0', '1', '2', '3', '4'])
deque.extendleft
Istotna jest również extendleft
metoda deque , która iteracyjnie przygotowuje:
>>> from collections import deque
>>> d2 = deque('def')
>>> d2.extendleft('cba')
>>> d2
deque(['a', 'b', 'c', 'd', 'e', 'f'])
Pamiętaj, że każdy element będzie dodawany jeden po drugim, co skutecznie odwróci ich kolejność.
Wydajność list
kontradeque
Najpierw konfigurujemy iteracyjne poprzedzanie:
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
i wydajność:
>>> 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 jest znacznie szybszy. Gdy listy będą coraz dłuższe, oczekiwałbym, że deque będzie działał jeszcze lepiej. Jeśli możesz użyć deque's extendleft
, prawdopodobnie uzyskasz w ten sposób najlepszą wydajność.