Cómo definir una matriz bidimensional en Python

726

Quiero definir una matriz bidimensional sin una longitud inicializada como esta:

Matrix = [][]

Pero no funciona...

He probado el siguiente código, pero también está mal:

Matrix = [5][5]

Error:

Traceback ...

IndexError: list index out of range

Cual es mi error?

Masoud Abasian
fuente
14
Uno no define matrices , ni ninguna otra cosa. Sin embargo, puede crear secuencias multidimensionales, como muestran las respuestas aquí. Recuerde que las variables de Python no están tipificadas, pero los valores están fuertemente tipificados.
SingleNegationElimination
1
Estoy confundido. Procedente de otros idiomas: ES una diferencia entre un 1D-Array que contiene 1D-Arrays y un 2D-Array. Y AFAIK no hay forma de tener una matriz (o lista) multidimensional en python. Debería decirse aquí ...
Dirk Reichel
1
Consulte también las preguntas frecuentes de Python3 sobre ¿Cómo creo una lista multidimensional?
Kevin W Matthews

Respuestas:

1011

Técnicamente está tratando de indexar una matriz no inicializada. Primero debe inicializar la lista externa con listas antes de agregar elementos; Python llama a esto "comprensión de la lista".

# Creates a list containing 5 lists, each of 8 items, all set to 0
w, h = 8, 5;
Matrix = [[0 for x in range(w)] for y in range(h)] 

Ahora puede agregar elementos a la lista:

Matrix[0][0] = 1
Matrix[6][0] = 3 # error! range... 
Matrix[0][6] = 3 # valid

Tenga en cuenta que la matriz es la dirección "y" mayor, en otras palabras, el "índice y" viene antes que el "índice x".

print Matrix[0][0] # prints 1
x, y = 0, 6 
print Matrix[x][y] # prints 3; be careful with indexing! 

Aunque puede nombrarlos como lo desee, lo veo de esta manera para evitar cierta confusión que pueda surgir con la indexación, si usa "x" para las listas internas y externas, y desea una matriz no cuadrada.

Manny D
fuente
219
[[0 para x en rango (cols_count)] para x en rango (rows_count)]
songhir
3
Edición impar por ademar111190. En Python 3 no hay xrange, pero si debe usar Python 2, entonces xrange es la función correcta para usar si no desea crear objetos innecesariamente.
Dave
44
@dave Si no lo necesita lleno de cero, puede usarlo rangepara crear las listas internas directamente:[range(5) for x in range(5)]
alanjds
2
@alanjds: eso es cierto, pero aún puede crear potencialmente muchas referencias de objetos innecesarios en Python 2 para la iteración externa (intente esto con un rango MUY grande). Además, la inicialización de algún valor es casi siempre lo que desea, y esto es más a menudo que no 0. el rango produce una colección iterable: xrange devuelve un generador. Mi punto era que Ademar "corrigió" algo que en realidad era más generalmente correcto y eficiente que su corrección.
Dave
10
@ 6packkid la [0] * wparte es agradable, pero [[0] * w] * h]producirá un comportamiento inesperado. Pruebe mat = [[0] * 3] * 3; mat[0][1] = 10; print(mat == [[0, 10, 0], [0, 10, 0], [0, 10, 0]])y mat = [[0] * 3 for i in range(3)]; mat[0][1] = 10; print(mat == [[0, 10, 0], [0, 0, 0], [0, 0, 0]]).
senderle
408

Si realmente quieres una matriz, es mejor que la uses numpy. Las operaciones matriciales en la numpymayoría de los casos usan un tipo de matriz con dos dimensiones. Hay muchas formas de crear una nueva matriz; una de las más útiles es la zerosfunción, que toma un parámetro de forma y devuelve una matriz de la forma dada, con los valores inicializados a cero:

>>> import numpy
>>> numpy.zeros((5, 5))
array([[ 0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.]])

Aquí hay algunas otras formas de crear matrices y matrices en 2-d (con salida eliminada por compacidad):

numpy.arange(25).reshape((5, 5))         # create a 1-d range and reshape
numpy.array(range(25)).reshape((5, 5))   # pass a Python range and reshape
numpy.array([5] * 25).reshape((5, 5))    # pass a Python list and reshape
numpy.empty((5, 5))                      # allocate, but don't initialize
numpy.ones((5, 5))                       # initialize with ones

numpytambién proporciona un matrixtipo, pero ya no se recomienda para ningún uso y puede eliminarse numpyen el futuro.

senderle
fuente
80
Siempre que quieras matrices, debes usar numpy. Esta respuesta debería ser la primera.
Pat B
3
El hecho de que la pregunta use la palabra inglesa "matrix" no significa que deberían usarla np.matrixpara representarla. La forma correcta de representar una matriz en numpy es con un array.
user2357112 es compatible con Monica el
@ user2357112, y como puede ver, la mayoría de los ejemplos enumerados anteriormente generan arrays en lugar de matrices. Si bien no siempre se recomienda, existen razones legítimas para usar matrix: el contexto es importante.
senderle
1
@senderle, ¿Puedes ampliar las razones para usar matrix? Desde @que se introdujo el operador, parece haber una razón menos desde que se escribió esta publicación.
jpp
1
@jpp, como decía la publicación anteriormente, las personas que vienen de matlab podrían encontrarlo útil. Pero los numpydocumentos ahora indican que la clase puede ser desaprobada y eliminada en el futuro, por lo que la saqué de la respuesta.
senderle
337

Aquí hay una notación más corta para inicializar una lista de listas:

matrix = [[0]*5 for i in range(5)]

Desafortunadamente, acortar esto a algo así 5*[5*[0]]no funciona realmente porque terminas con 5 copias de la misma lista, por lo que cuando modificas una de ellas, todas cambian, por ejemplo:

>>> matrix = 5*[5*[0]]
>>> matrix
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
>>> matrix[4][4] = 2
>>> matrix
[[0, 0, 0, 0, 2], [0, 0, 0, 0, 2], [0, 0, 0, 0, 2], [0, 0, 0, 0, 2], [0, 0, 0, 0, 2]]
Andrew Clark
fuente
44
¿Podría explicar la lógica detrás del fracaso del "acortamiento"? ¿Por qué Python genera copias de la misma lista en este caso, y una matriz de celdas diferentes en el caso de [0]*5?
mike622867
12
Los comentarios anteriores no son exactamente ciertos: [0] * 5 todavía crea una secuencia con 5 veces una referencia al mismo Objeto que representa el número 0. Pero nunca lo notará porque 0 es inmutable (diría que 0 se comporta como un valor - o podría considerarlo como un tipo de datos primitivo - porque es inmutable, por lo que nunca tendrá problemas con las referencias al mismo objeto en lugar de tener copias.)
dreua
44
más pitónico: [[0]*5 for _ in range(5)]con contador de bucle anónimo que no estás usando
Jean-François Fabre
Es bueno que señales el problema de la copia superficial en el segundo ejemplo.
whatacold
gracias @dreua, estaba realmente confundido sobre cómo [0]*5funciona bien. Ahora entiendo por qué [{0}]*8sería una mala idea también.
kuku
110

Si desea crear una matriz vacía, la sintaxis correcta es

matrix = [[]]

Y si desea generar una matriz de tamaño 5 con 0,

matrix = [[0 for i in xrange(5)] for i in xrange(5)]
mripard
fuente
@KorayTugay Debido a que la matriz se representa usando las listas de Python (las filas) anidadas dentro de otra lista (las columnas).
eleg
2
Para Python-3 use la función de rango en lugar de xrange func
Rakesh Chaudhari
77

Si todo lo que desea es un contenedor bidimensional para contener algunos elementos, puede utilizar convenientemente un diccionario en su lugar:

Matrix = {}

Entonces puedes hacer:

Matrix[1,2] = 15
print Matrix[1,2]

Esto funciona porque 1,2es una tupla, y la estás usando como clave para indexar el diccionario. El resultado es similar a una matriz dispersa tonta.

Como lo indican osa y Josap Valls, también puede usar Matrix = collections.defaultdict(lambda:0)para que los elementos faltantes tengan un valor predeterminado de 0.

Vatsal señala además que este método probablemente no sea muy eficiente para matrices grandes y solo debe usarse en partes del código que no sean críticas para el rendimiento.

enobayram
fuente
2
Entonces también puede hacerlo import collections; Matrix = collections.defaultdict(float), para sustituir ceros por elementos no inicializados.
osa
2
No acceder a un dict para tupla (1,2) como clave tiene una peor complejidad de O (n). Como internamente, picaría las tuplas. Mientras que el uso de una matriz 2D le daría a O (1) complejidad de tiempo para acceder al índice [1,2]. Por lo tanto, usar dict para esto no debería ser una buena opción.
Vatsal
@Vatsal wiki.python.org/moin/TimeComplexity dice que el caso promedio es O (1), pero tiene razón sobre el peor de los casos. De todos modos, a menos que estés hablando de MUCHOS ARTÍCULOS, no te importaría esta diferencia. De hecho, me preocuparía más la memoria que el tiempo de acceso.
enobayram
También siempre tratamos de evitar el uso de dictos hasta que la complejidad general del algoritmo sea igual o mayor que O (n ^ 2). Como 'n' veces los accesos O (n) darían una complejidad O (n ^ 2).
Vatsal
@enobayram, lo siento pero no estoy de acuerdo. El análisis asintótico siempre dará O (n ^ 2), si el peor de los casos, el acceso O (n) se realiza 'n' veces. Donde como análisis Amortized puede dar un límite menor. Y hay una gran diferencia entre el caso amortizado y el promedio ... consulte antes de hacer suposiciones y comentarios vagos
Vatsal
42

En Python crearás una lista de listas. No tiene que declarar las dimensiones con anticipación, pero puede hacerlo. Por ejemplo:

matrix = []
matrix.append([])
matrix.append([])
matrix[0].append(2)
matrix[1].append(3)

Ahora matriz [0] [0] == 2 y matriz [1] [0] == 3. También puede usar la sintaxis de comprensión de la lista. Este ejemplo lo usa dos veces para construir una "lista bidimensional":

from itertools import count, takewhile
matrix = [[i for i in takewhile(lambda j: j < (k+1) * 10, count(k*10))] for k in range(10)]
fresa
fuente
66
extendTambién sería útil en el primer caso: si comienza con m = [[]], entonces podría agregar a la lista interna (extender una fila) con m[0].extend([1,2]), y agregar a la lista externa (agregar una nueva fila) con m.append([3,4]), esas operaciones lo dejarían con [[1, 2], [3, 4]].
askewchan
22

La respuesta aceptada es buena y correcta, pero me llevó un tiempo comprender que también podría usarla para crear una matriz completamente vacía.

l =  [[] for _ in range(3)]

resultados en

[[], [], []]
Fabian
fuente
22

Debería hacer una lista de listas, y la mejor manera es usar comprensiones anidadas:

>>> matrix = [[0 for i in range(5)] for j in range(5)]
>>> pprint.pprint(matrix)
[[0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0]]

En su [5][5]ejemplo, está creando una lista con un número entero "5" dentro, e intenta acceder a su quinto elemento, y eso naturalmente genera un IndexError porque no hay un quinto elemento:

>>> l = [5]
>>> l[5]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range
utdemir
fuente
En realidad, la secuencia para row_index ('i') y column_index ('j') es la siguiente: '>>> matrix = [[0 para column_index en range (5)] para row_index en range (5)]'
Aniruddha Kalburgi
22
rows = int(input())
cols = int(input())

matrix = []
for i in range(rows):
  row = []
  for j in range(cols):
    row.append(0)
  matrix.append(row)

print(matrix)

¿Por qué un código tan largo que también Pythonpreguntas?

Hace mucho tiempo, cuando no me sentía cómodo con Python, vi las respuestas de una sola línea para escribir una matriz 2D y me dije a mí mismo que no voy a usar la matriz 2-D en Python nuevamente. (Esas líneas individuales daban bastante miedo y no me dieron ninguna información sobre lo que estaba haciendo Python. También tenga en cuenta que no estoy al tanto de estas shorthands).

De todos modos, aquí está el código para un principiante cuyo origen es C, CPP y Java.

Nota para los amantes y expertos de Python: por favor no voten solo porque escribí un código detallado.

error desconocido
fuente
13

Una reescritura para una fácil lectura:

# 2D array/ matrix

# 5 rows, 5 cols
rows_count = 5
cols_count = 5

# create
#     creation looks reverse
#     create an array of "cols_count" cols, for each of the "rows_count" rows
#        all elements are initialized to 0
two_d_array = [[0 for j in range(cols_count)] for i in range(rows_count)]

# index is from 0 to 4
#     for both rows & cols
#     since 5 rows, 5 cols

# use
two_d_array[0][0] = 1
print two_d_array[0][0]  # prints 1   # 1st row, 1st col (top-left element of matrix)

two_d_array[1][0] = 2
print two_d_array[1][0]  # prints 2   # 2nd row, 1st col

two_d_array[1][4] = 3
print two_d_array[1][4]  # prints 3   # 2nd row, last col

two_d_array[4][4] = 4
print two_d_array[4][4]  # prints 4   # last row, last col (right, bottom element of matrix)
Manohar Reddy Poreddy
fuente
13

Utilizar:

matrix = [[0]*5 for i in range(5)]

El * 5 para la primera dimensión funciona porque a este nivel los datos son inmutables.

innov8
fuente
55
Probablemente escribiría esto comomatrix = [[0]*cols for _ in range(rows)]
Shital Shah
12

Para declarar una matriz de ceros (unos):

numpy.zeros((x, y))

p.ej

>>> numpy.zeros((3, 5))
    array([[ 0.,  0.,  0.,  0.,  0.],
   [ 0.,  0.,  0.,  0.,  0.],
   [ 0.,  0.,  0.,  0.,  0.]])

o numpy.ones ((x, y)) ej.

>>> np.ones((3, 5))
array([[ 1.,  1.,  1.,  1.,  1.],
   [ 1.,  1.,  1.,  1.,  1.],
   [ 1.,  1.,  1.,  1.,  1.]])

Incluso tres dimensiones son posibles. ( http://www.astro.ufl.edu/~warner/prog/python.html ver -> Arreglos multidimensionales)

khaz
fuente
12

Así es como generalmente creo matrices 2D en python.

col = 3
row = 4
array = [[0] * col for _ in range(row)]

Encuentro esta sintaxis fácil de recordar en comparación con el uso de dos bucles for en una lista de comprensión.

Miguel
fuente
11

Estoy en mi primer script de Python, y estaba un poco confundido con el ejemplo de matriz cuadrada, así que espero que el siguiente ejemplo lo ayude a ahorrar algo de tiempo:

 # Creates a 2 x 5 matrix
 Matrix = [[0 for y in xrange(5)] for x in xrange(2)]

así que eso

Matrix[1][4] = 2 # Valid
Matrix[4][1] = 3 # IndexError: list index out of range
usuario110954
fuente
10

Usando NumPy puedes inicializar una matriz vacía como esta:

import numpy as np
mm = np.matrix([])

Y luego agregue datos como este:

mm = np.append(mm, [[1,2]], axis=1)
Namrata Tolani
fuente
¿Cuáles serían las ventajas y desventajas de usar numpy en lugar de "lista de comprensión"?
Revolución para Monica
7

Leí en archivos separados por comas como este:

data=[]
for l in infile:
    l = split(',')
    data.append(l)

La lista "datos" es entonces una lista de listas con datos de índice [fila] [col]

wsanders
fuente
7

Si desea poder pensarlo como una matriz 2D en lugar de verse obligado a pensar en términos de una lista de listas (mucho más natural en mi opinión), puede hacer lo siguiente:

import numpy
Nx=3; Ny=4
my2Dlist= numpy.zeros((Nx,Ny)).tolist()

El resultado es una lista (no una matriz NumPy), y puede sobrescribir las posiciones individuales con números, cadenas, lo que sea.

alessadnro
fuente
son numpy.matrixequivalentes a numpy.zerossin ceros sin ser lista?
Revolución para Monica
6

Eso es lo que el diccionario está hecho el !

matrix = {}

Puedes definir claves y valores de dos maneras:

matrix[0,0] = value

o

matrix = { (0,0)  : value }

Resultado:

   [ value,  value,  value,  value,  value],
   [ value,  value,  value,  value,  value],
   ...
Mohammad Mahdi KouchakYazdi
fuente
6

Utilizar:

import copy

def ndlist(*args, init=0):
    dp = init
    for x in reversed(args):
        dp = [copy.deepcopy(dp) for _ in range(x)]
    return dp

l = ndlist(1,2,3,4) # 4 dimensional list initialized with 0's
l[0][1][2][3] = 1

Creo que NumPy es el camino a seguir. Lo anterior es genérico si no desea usar NumPy.

pterodragon
fuente
Me gusta este intento de hacer algo simple con Python vainilla sin tener que usar numpy.
Rick Henderson
4

mediante el uso de la lista:

matrix_in_python  = [['Roy',80,75,85,90,95],['John',75,80,75,85,100],['Dave',80,80,80,90,95]]

mediante el uso de dict: también puede almacenar esta información en la tabla hash para realizar búsquedas rápidas como

matrix = { '1':[0,0] , '2':[0,1],'3':[0,2],'4' : [1,0],'5':[1,1],'6':[1,2],'7':[2,0],'8':[2,1],'9':[2,2]};

matriz ['1'] le dará resultado en O (1) tiempo

* nb : debes lidiar con una colisión en la tabla hash

Saurabh Chandra Patel
fuente
4

Si no tiene información sobre el tamaño antes de comenzar, cree dos listas unidimensionales.

list 1: To store rows
list 2: Actual two-dimensional matrix

Almacene toda la fila en la primera lista. Una vez hecho esto, agregue la lista 1 a la lista 2:

from random import randint

coordinates=[]
temp=[]
points=int(raw_input("Enter No Of Coordinates >"))
for i in range(0,points):
    randomx=randint(0,1000)
    randomy=randint(0,1000)
    temp=[]
    temp.append(randomx)
    temp.append(randomy)
    coordinates.append(temp)

print coordinates

Salida:

Enter No Of Coordinates >4
[[522, 96], [378, 276], [349, 741], [238, 439]]
Nagendra Nigade
fuente
3
# Creates a list containing 5 lists initialized to 0
Matrix = [[0]*5]*5

Tenga cuidado con esta breve expresión, vea la explicación completa en la respuesta de @ FJ

和風 信使
fuente
19
Tenga cuidado de esta manera, porque Matrix[0], Matrix[1], ..., Matrix[4]todos apuntan a la misma matriz, por lo que después Matrix[0][0] = 3esperaría Matrix[0][0] == Matrix[1][0] == ... == Matrix[4][0] == 3.
gongzhitaao
1
Gracias gongzhitaao por tu comentario. Si lo hubiera leído antes, me habría ahorrado al menos media hora. Tener una matriz donde cada fila apunte al mismo lugar en la memoria no parece ser muy útil, y si no eres consciente de lo que estás haciendo ¡Incluso es peligroso! Estoy bastante seguro de que esto NO es lo que Masoud Abasian, quien hizo la pregunta, quiere hacer.
Adrian
77
Debe eliminar esta respuesta, ya que no es la respuesta correcta. Los principiantes pueden estar confundidos.
cxxl
2
¿A qué respuesta te refieres? No veo un usuario con el nombre "FJ" (ni siquiera en las respuestas eliminadas).
Peter Mortensen
3
l=[[0]*(L) for _ in range(W)]

Será más rápido que:

l = [[0 for x in range(L)] for y in range(W)] 
Sharma áspero
fuente
2
La respuesta duplicada de una ya respondió a continuación. También [[0]*(L) for i in range(W)]debería ser [[0]*(L) for _ in range(W)]ya ique no se usa en ninguna parte
Ayush Vatsyayan
2

Puede crear una lista bidimensional vacía anidando dos o más arriostramientos cuadrados o tercer corchete ( [], separados por comas) con un arriostramiento cuadrado, tal como se muestra a continuación:

Matrix = [[], []]

Ahora suponga que desea agregar 1 y Matrix[0][0]luego escribe:

Matrix[0].append(1)

Ahora, escribe Matrix y presiona Enter. El resultado será:

[[1], []]
Meraj al Maksud
fuente
1

Prueba esto:

rows = int(input('Enter rows\n'))
my_list = []
for i in range(rows):
    my_list.append(list(map(int, input().split())))
Ankit Sharma
fuente
1

En caso de que necesite una matriz con números predefinidos, puede usar el siguiente código:

def matrix(rows, cols, start=0):
    return [[c + start + r * cols for c in range(cols)] for r in range(rows)]


assert matrix(2, 3, 1) == [[1, 2, 3], [4, 5, 6]]
Vlad Bezden
fuente
1

Aquí está el fragmento de código para crear una matriz en python:

# get the input rows and cols
rows = int(input("rows : "))
cols = int(input("Cols : "))

# initialize the list
l=[[0]*cols for i in range(rows)]

# fill some random values in it
for i in range(0,rows):
    for j in range(0,cols):
        l[i][j] = i+j

# print the list
for i in range(0,rows):
    print()
    for j in range(0,cols):
        print(l[i][j],end=" ")

Por favor sugiera si me he perdido algo.

Chandra Shekhar
fuente