¿Cuál es la sintaxis idiomática para anteponer a una lista corta de Python?
Por lo general, no desea anteponer repetidamente a una lista en Python.
Si es corto , y no lo estás haciendo mucho ... entonces está bien.
list.insert
El list.insert
puede ser usado de esta manera.
list.insert(0, x)
Pero esto es ineficiente, porque en Python, a list
es una matriz de punteros, y Python ahora debe tomar cada puntero en la lista y moverlo hacia abajo para insertar el puntero en su objeto en la primera ranura, por lo que esto es realmente eficiente para listas más bien cortas, como preguntas.
Aquí hay un fragmento de la fuente CPython donde se implementa esto, y como puede ver, comenzamos al final de la matriz y movemos todo hacia abajo por uno para cada inserción:
for (i = n; --i >= where; )
items[i+1] = items[i];
Si desea un contenedor / lista que sea eficiente para anteponer elementos, desea una lista vinculada. Python tiene una lista doblemente vinculada, que se puede insertar al principio y al final rápidamente, se llama a deque
.
deque.appendleft
A collections.deque
tiene muchos de los métodos de una lista. list.sort
es una excepción, por lo que deque
definitivamente no es completamente sustituible por Liskov list
.
>>> set(dir(list)) - set(dir(deque))
{'sort'}
El deque
también tiene un appendleft
método (así como popleft
). El deque
es una cola de doble extremo y una lista doblemente enlazada: no importa la longitud, siempre lleva la misma cantidad de tiempo pretender algo. En la notación O grande, O (1) versus el tiempo O (n) para las listas. Aquí está el uso:
>>> import collections
>>> d = collections.deque('1234')
>>> d
deque(['1', '2', '3', '4'])
>>> d.appendleft('0')
>>> d
deque(['0', '1', '2', '3', '4'])
deque.extendleft
También es relevante el extendleft
método de deque , que antecede iterativamente:
>>> from collections import deque
>>> d2 = deque('def')
>>> d2.extendleft('cba')
>>> d2
deque(['a', 'b', 'c', 'd', 'e', 'f'])
Tenga en cuenta que cada elemento se antepondrá uno a la vez, invirtiendo efectivamente su orden.
Rendimiento de list
versusdeque
Primero configuramos con algunos pretendientes iterativos:
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
y rendimiento:
>>> 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
El deque es mucho más rápido. A medida que las listas se alarguen, esperaría que una deque funcione aún mejor. Si puede usar deque extendleft
probablemente obtendrá el mejor rendimiento de esa manera.