Python List vs. Array: ¿cuándo usarlo?

375

Si está creando una matriz 1d, puede implementarla como una Lista, o bien usar el módulo 'matriz' en la biblioteca estándar. Siempre he usado Listas para matrices 1d.

¿Cuál es la razón o circunstancia en la que me gustaría utilizar el módulo de matriz en su lugar?

¿Es para optimizar el rendimiento y la memoria, o me falta algo obvio?

Corey Goldberg
fuente

Respuestas:

438

Básicamente, las listas de Python son muy flexibles y pueden contener datos completamente heterogéneos y arbitrarios, y se pueden agregar de manera muy eficiente, en tiempo constante amortizado . Si necesita reducir y hacer crecer su lista de manera eficiente en el tiempo y sin problemas, son el camino a seguir. Pero utilizan un espacio mucho más que C matrices .

El array.arraytipo, por otro lado, es solo una envoltura delgada en matrices C. Solo puede contener datos homogéneos, todos del mismo tipo, por lo que solo utiliza sizeof(one object) * lengthbytes de memoria. Principalmente, debe usarlo cuando necesite exponer una matriz C a una extensión o una llamada al sistema (por ejemplo, ioctlo fctnl).

array.arrayTambién es una forma razonable de representar una cadena mutable en Python 2.x ( array('B', bytes)). Sin embargo, Python 2.6+ y 3.x ofrece una cadena de bytes mutable como bytearray.

Sin embargo, si desea hacer cálculos matemáticos en una matriz homogénea de datos numéricos, entonces es mucho mejor usar NumPy, que puede vectorizar automáticamente las operaciones en matrices multidimensionales complejas.

En pocas palabras : array.arrayes útil cuando necesita una matriz de datos C homogénea por otras razones que no sean matemáticas .

Dan Lenski
fuente
99
¿Numpy.ndarray tiene la misma huella de memoria que array.array?
Gordon Bean
66
@ Gordon, debería ser muy similar en el caso de una matriz contigua grande: ambos requerirán sizeof(element)× (número de elementos) bytes, más un pequeño encabezado fijo para la sobrecarga. Sin embargo, ndarray tiene algunas opciones avanzadas para manejar matrices poco contiguas y dispersas, y creo que algunas estrategias conectables para asignar memoria para matrices grandes ... algunas de estas características avanzadas harán que el usuario tenga menos memoria, mientras que otras mejorarán el rendimiento al usar más memoria.
Dan Lenski
También es útil cuando la memoria es un problema, como cuando se programan microcontroladores con micropython
janscas
Uno puede buscar el i-ésimo elemento de una matriz en un tiempo constante, mientras que en la lista vinculada, toma el orden 'n' en el peor de los casos. ¿Cuál es el tiempo de búsqueda del elemento i en una lista de Python?
Nithish Inpursuit Ofhappiness
77
@NithishInpursuitOfhappiness, una lista de Python no es una lista vinculada. Se representa internamente como una matriz y tiene las mismas características de complejidad de tiempo que la ArrayList de Java. Por lo tanto, obtener y establecer el i-ésimo elemento de una lista de Python lleva tiempo constante . Agregar un elemento a una lista de Python lleva tiempo constante amortizado porque el tamaño de la matriz se duplica cuando se queda sin espacio. Insertar un elemento o eliminarlo del medio de una lista de Python lleva O (n) tiempo porque los elementos deben cambiarse. Para referencia, consulte: wiki.python.org/moin/TimeComplexity
geofflee
66

Para casi todos los casos, la lista normal es la elección correcta. El módulo de matrices se parece más a una envoltura delgada sobre matrices en C, que le dan un tipo de contenedores fuertemente tipados (ver documentos ), con acceso a más tipos similares a C, como con signo / sin signo, corto o doble, que no son parte de la construcción -en tipos. Yo diría que use el módulo de matrices solo si realmente lo necesita, en todos los demás casos, quédese con las listas.

André
fuente
3
Posiblemente, nunca lo usé realmente, pero sería interesante ejecutar algunos micro benchmarks.
André
13
En realidad, hice una prueba rápida: cronometré la suma de una lista con 100 millones de entradas y la misma prueba con la matriz correspondiente, y la lista fue en realidad un 10% más rápida.
Moe
38
Las listas son más rápidas, porque las operaciones en los datos "en bruto" de la matriz necesitan crear y destruir continuamente objetos de Python al leer o escribir en la matriz.
tzot
77
@Moe, como señalé en mi respuesta anterior, el incorporado de Python noarray está destinado a hacer matemáticas . Si intentas NumPy's ndarraypara sumar una matriz de 10 ^ 8 números, se irá por completo list. @tzot tiene la idea correcta de por qué la integración arrayes lenta para las matemáticas.
Dan Lenski
2
Lo acabo de probar, numpy es 86.6x más rápido en mi máquina.
Mark
53

El módulo de matriz es una de esas cosas que probablemente no necesite si no sabe por qué lo usaría (¡y tenga en cuenta que no estoy tratando de decir eso de manera condescendiente!) . La mayoría de las veces, el módulo de matriz se usa para interactuar con el código C. Para darle una respuesta más directa a su pregunta sobre el rendimiento:

Las matrices son más eficientes que las listas para algunos usos. Si necesita asignar una matriz que SABE que no cambiará, las matrices pueden ser más rápidas y usar menos memoria. GvR tiene una anécdota de optimización en la que el módulo de matriz resulta ser el ganador (lectura larga, pero vale la pena).

Por otro lado, parte de la razón por la cual las listas consumen más memoria que las matrices es porque python asignará algunos elementos adicionales cuando se usen todos los elementos asignados. Esto significa que agregar elementos a las listas es más rápido. Entonces, si planea agregar elementos, una lista es el camino a seguir.

TL; DR Solo usaría una matriz si tuviera una necesidad de optimización excepcional o si necesita interactuar con el código C (y no puede usar pyrex ).

Jason Baker
fuente
1
+1 por ejemplo concreto y mencionando el beneficio de velocidad. La respuesta principal me hizo preguntarme: "¿Hay una compensación de memoria de tiempo?" y "¿Hay algún uso para esto que no sea un caso muy esotérico de poca memoria?"
leewz
@leewz exactamente, esto debe considerarse como respuesta.
Gauri Shankar Badola
21

¡Es una compensación!

Ventajas de cada uno:

lista

  • flexible
  • puede ser heterogéneo

matriz (por ejemplo: matriz numpy)

  • conjunto de valores uniformes
  • homogéneo
  • compacto (en tamaño)
  • eficiente (funcionalidad y velocidad)
  • conveniente
Mohammad Mahdi KouchakYazdi
fuente
2
la pregunta se refiere al módulo de matriz en python; no matrices numpy. No tienen muchos profesionales, excepto la eficiencia de tamaño. No son mas rapidos.
NONONONONO
14

Entiendo que las matrices se almacenan de manera más eficiente (es decir, como bloques contiguos de memoria frente a punteros a objetos Python), pero no conozco ningún beneficio de rendimiento. Además, con las matrices debe almacenar primitivas del mismo tipo, mientras que las listas pueden almacenar cualquier cosa.

Ben Hoffstein
fuente
8

Las matrices de biblioteca estándar son útiles para E / S binarias, como traducir una lista de entradas a una cadena para escribir, por ejemplo, en un archivo wave. Dicho esto, como muchos ya han notado, si vas a hacer un trabajo real, entonces deberías considerar usar NumPy.

Giltay
fuente
6

Si va a utilizar matrices, considere los paquetes numpy o scipy, que le brindan matrices con mucha más flexibilidad.

Alex Coventry
fuente
5

La matriz solo se puede usar para tipos específicos, mientras que las listas se pueden usar para cualquier objeto.

Las matrices también pueden solo datos de un tipo, mientras que una lista puede tener entradas de varios tipos de objetos.

Las matrices también son más eficientes para algunos cálculos numéricos.

Hortitude
fuente
44
Los arrays de python incorporados no son eficientes en cuanto al rendimiento, solo en cuanto a memoria.
tzot
Hay instancias donde los arreglos son más eficientes en términos de procesamiento. Vea mi publicación a continuación: stackoverflow.com/questions/176011/…
Jason Baker,
0

Una diferencia importante entre la matriz numpy y la lista es que las secciones de la matriz son vistas en la matriz original. Esto significa que los datos no se copian y cualquier modificación de la vista se reflejará en la matriz de origen.

vivek
fuente
0

Esta respuesta resumirá casi todas las consultas sobre cuándo usar List and Array:

  1. La principal diferencia entre estos dos tipos de datos son las operaciones que puede realizar en ellos. Por ejemplo, puede dividir una matriz por 3 y dividirá cada elemento de la matriz por 3. No se puede hacer lo mismo con la lista.

  2. La lista es parte de la sintaxis de Python, por lo que no es necesario declararla, ya que debe declarar la matriz antes de usarla.

  3. Puede almacenar valores de diferentes tipos de datos en una lista (heterogéneos), mientras que en Array solo puede almacenar valores del mismo tipo de datos (homogéneos).

  4. Las matrices son ricas en funcionalidades y rápidas, se usan ampliamente para operaciones aritméticas y para almacenar una gran cantidad de datos, en comparación con la lista.

  5. Las matrices toman menos memoria en comparación con las listas.

Dipen Gajjar
fuente
0

Con respecto al rendimiento, aquí hay algunos números que comparan listas de python, matrices y matrices numpy (todas con Python 3.7 en un Macbook Pro 2017). El resultado final es que la lista de Python es la más rápida para estas operaciones.

# Python list with append()
np.mean(timeit.repeat(setup="a = []", stmt="a.append(1.0)", number=1000, repeat=5000)) * 1000
# 0.054 +/- 0.025 msec

# Python array with append()
np.mean(timeit.repeat(setup="import array; a = array.array('f')", stmt="a.append(1.0)", number=1000, repeat=5000)) * 1000
# 0.104 +/- 0.025 msec

# Numpy array with append()
np.mean(timeit.repeat(setup="import numpy as np; a = np.array([])", stmt="np.append(a, [1.0])", number=1000, repeat=5000)) * 1000
# 5.183 +/- 0.950 msec

# Python list using +=
np.mean(timeit.repeat(setup="a = []", stmt="a += [1.0]", number=1000, repeat=5000)) * 1000
# 0.062 +/- 0.021 msec

# Python array using += 
np.mean(timeit.repeat(setup="import array; a = array.array('f')", stmt="a += array.array('f', [1.0]) ", number=1000, repeat=5000)) * 1000
# 0.289 +/- 0.043 msec

# Python list using extend()
np.mean(timeit.repeat(setup="a = []", stmt="a.extend([1.0])", number=1000, repeat=5000)) * 1000
# 0.083 +/- 0.020 msec

# Python array using extend()
np.mean(timeit.repeat(setup="import array; a = array.array('f')", stmt="a.extend([1.0]) ", number=1000, repeat=5000)) * 1000
# 0.169 +/- 0.034
Hefesto
fuente