2011-12-21 13 views
6

Cuando iterar a través de los valores de list1start-stop, como en:Python: ¿una iteración a través de 'list [a: b]' copia primero esa parte de la lista (que podría ser costosa)?

for value in list1[start:stop]: 
    .... 

¿Se pitón ejemplar de la primera parte de la lista (como se hace cuando se hace list2 = list1[:])? ¡Esto podría ser muy costoso para listas grandes!

Si no lo copia en el ejemplo anterior, ¿eso siempre es cierto? Necesito hacer el siguiente tipo de bucle, muy a menudo, en grandes sectores de (muy) grandes listas:

for index, value in enumerate(list1[start:stop], start): 
    .... 
+0

¿Pero 'list1' en realidad necesita ser una * lista *? Creo que no daría lugar a ninguna copia si 'list1' fuera, por ejemplo, una matriz Numpy. –

+0

@AndrewJaffe - No, siempre que una matriz Numpy pueda manejar matrices de tuplas/enteros/cadenas/sub'Numpy ', es decir, una variedad de tipos de datos de diferentes tamaños. No sé nada sobre numpy sin embargo, y el módulo 'array' enviado con Python no aparece (en mis pruebas de perfil) para hacer una gran diferencia, en su caso. – Jeff

Respuesta

8

list1[start:stop] crea una nueva lista, y punto. Este es siempre el caso, independientemente de si itera sobre el resultado directamente o tiene una función intermedia o la usa en cualquier otro contexto (necesitaría un lenguaje moderadamente estático o una inferencia de tipo sofisticada para optimizar incluso para un simple instancias del primer caso).

Tenga en cuenta que esto es independiente de la iteración! La iteración en sí no se copia, y la lista corta las copias incluso si arroja el resultado.

Sin embargo, solo copia los punteros, por lo que si siempre toma sublistas muy pequeñas, probablemente no notaría ninguna diferencia. Si las sublistas son más grandes, puede iterar sobre los índices ([x]range) o usar itertools.islice. Sin embargo, este último debería omitir los artículos start primero, por lo que es posible que pague una considerable penalidad por el ahorro de memoria. El primero es feo, pero el más eficiente asintomáticamente.

+0

¿Es una operación lenta tener acceso repetidamente a índices altos en listas grandes? En otras palabras, ¿me beneficio al hacer 'para el índice en el rango (inicio, parada): #hacer algo con 'lista [índice]' 'vs' para el valor en la lista [inicio: detener]: #hacer algo con 'valor' ? – Jeff

+1

@Jeff: [acceso a la lista] (http://wiki.python.org/moin/TimeComplexity) es el O (1) peor caso, es decir, independiente del índice y el tamaño de la matriz. Lo que Python llama una lista es realmente una matriz dinámica y sobreasignable. – delnan

+0

@Jeff: ¿Por qué no solo lo comparas? No es una molestia –

2

Sí.

La expresión list1[start:stop] crea una nueva lista que contiene los elementos en el rango especificado. Sin embargo, no está copiando los datos reales, solo un conjunto de punteros, por lo que a menos que la lista sea muy larga, la sobrecarga normalmente no importará.

1

En lugar de hacer esta pregunta, usted podría tener simplemente probado esto con el método de identificación mágica

>>> x=[1,2,3,4] 
>>> id(x[1]) 
4971620 
>>> id(x[1:][0]) #same as the original list 
4971620 
>>> id(x[2:3]) 
44327400 
>>> id(x) 
44408224 
>>> 

x[2:3] realidad crea una nueva lista, pero los elementos aún se hace referencia a la lista original.

+1

* Los artículos * son iguales. La pregunta es: ¿Se ha creado una nueva lista? (Además, los enteros pequeños son datos de prueba malos ya que están en caché y por lo tanto '[1, 2] [0] es [0, 1] [1]') – delnan

Cuestiones relacionadas