Was ist die idiomatische Syntax für das Voranstellen einer kurzen Python-Liste?
Normalerweise möchten Sie einer Liste in Python nicht wiederholt voranstellen.
Wenn es kurz ist und du es nicht viel machst ... dann ok.
list.insert
Das list.insert
kann auf diese Weise verwendet werden.
list.insert(0, x)
Dies ist jedoch ineffizient, da in Python a list
ein Array von Zeigern ist und Python nun jeden Zeiger in der Liste um eins nach unten verschieben muss, um den Zeiger auf Ihr Objekt im ersten Slot einzufügen. Dies ist also wirklich nur effizient für eher kurze Listen, wie Sie fragen.
Hier ist ein Ausschnitt aus der CPython-Quelle, in der dies implementiert ist. Wie Sie sehen können, beginnen wir am Ende des Arrays und verschieben bei jeder Einfügung alles um eins nach unten:
for (i = n; --i >= where; )
items[i+1] = items[i];
Wenn Sie einen Container / eine Liste wünschen, mit dem Elemente effizient vorangestellt werden können, möchten Sie eine verknüpfte Liste. Python hat eine doppelt verknüpfte Liste, die am Anfang und am Ende schnell eingefügt werden kann - sie heißt a deque
.
deque.appendleft
A collections.deque
hat viele Methoden einer Liste. list.sort
ist eine Ausnahme, die deque
Liskov definitiv nicht vollständig ersetzbar macht list
.
>>> set(dir(list)) - set(dir(deque))
{'sort'}
Das deque
hat auch eine appendleft
Methode (sowie popleft
). Es deque
handelt sich um eine Warteschlange mit zwei Enden und eine doppelt verknüpfte Liste - unabhängig von der Länge dauert es immer genauso lange, bis etwas angezeigt wird. In der großen O-Notation ist O (1) gegen die O (n) -Zeit für Listen. Hier ist die Verwendung:
>>> import collections
>>> d = collections.deque('1234')
>>> d
deque(['1', '2', '3', '4'])
>>> d.appendleft('0')
>>> d
deque(['0', '1', '2', '3', '4'])
deque.extendleft
Ebenfalls relevant ist die extendleft
Methode der Deque , die iterativ Folgendes vorstellt:
>>> from collections import deque
>>> d2 = deque('def')
>>> d2.extendleft('cba')
>>> d2
deque(['a', 'b', 'c', 'd', 'e', 'f'])
Beachten Sie, dass jedem Element ein einzelnes vorangestellt wird, wodurch die Reihenfolge effektiv umgekehrt wird.
Leistung von list
versusdeque
Zuerst richten wir mit einem iterativen Voranstellen ein:
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
und Leistung:
>>> 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
Die Deque ist viel schneller. Wenn die Listen länger werden, würde ich erwarten, dass eine Deque noch besser abschneidet. Wenn Sie Deques verwenden können, extendleft
erzielen Sie auf diese Weise wahrscheinlich die beste Leistung.