¿Cómo inicializar una matriz bidimensional en Python?

262

Estoy empezando a usar Python e intento usar una lista bidimensional, que inicialmente llené con la misma variable en cada lugar. Se me ocurrió esto:

def initialize_twodlist(foo):
    twod_list = []
    new = []
    for i in range (0, 10):
        for j in range (0, 10):
            new.append(foo)
        twod_list.append(new)
        new = []

Da el resultado deseado, pero se siente como una solución alternativa. ¿Hay una manera más fácil / más corta / más elegante de hacer esto?

thepandaatemyface
fuente
77
Solo un pequeño (o significativo, dependiendo de quién lo esté mirando): las listas no son matrices. Si quieres matrices, usa numpy.
Arnab Datta
Esta pregunta es similar : discute la inicialización de matrices multidimensionales en Python.
Anderson Green
@ArnabDatta ¿Cómo inicializarías una matriz multidimensional en numpy, entonces?
Anderson Green
1
@AndersonGreen docs.scipy.org/doc/numpy/user/…
Arnab Datta
Puede organizar los datos en una matriz como estructura en Python predeterminado, pero no es tan eficiente o útil como una matriz NumPy. Especialmente si quieres lidiar con grandes conjuntos de datos. Aquí hay alguna documentación docs.scipy.org/doc/numpy-1.10.1/user/basics.creation.html
jmdeamer

Respuestas:

376

Un patrón que a menudo surgió en Python fue

bar = []
for item in some_iterable:
    bar.append(SOME EXPRESSION)

que ayudó a motivar la introducción de las comprensiones de listas, que convierten ese fragmento en

bar = [SOME EXPRESSION for item in some_iterable]

que es más corto y a veces más claro. Por lo general, tiene el hábito de reconocerlos y, a menudo, reemplazar los bucles con comprensiones.

Su código sigue este patrón dos veces

twod_list = []                                       \                      
for i in range (0, 10):                               \
    new = []                  \ can be replaced        } this too
    for j in range (0, 10):    } with a list          /
        new.append(foo)       / comprehension        /
    twod_list.append(new)                           /
Mike Graham
fuente
35
Por cierto, [[foo] * 10 para x en xrange (10)] se puede utilizar para deshacerse de una comprensión. El problema es que la multiplicación hace una copia superficial, por lo que new = [foo] * 10 new = [new] * 10 obtendrá una lista que contiene la misma lista diez veces.
Scott Wolchok
8
Del mismo modo, [foo] * 10es una lista con exactamente las mismas foo10 veces, que puede o no ser importante.
Mike Graham
2
podemos usar lo más simple: wtod_list = [[0 para x en xrange (10))] para x en xrange (10)]
indi60
2
Sin embargo, nunca está de más mostrarle a alguien cómo es un pez.
Csteele5
2
Para el comentario de Mike Graham sobre [foo] * 10: Esto significa que este no funcionaría si usted está llenando una matriz con números aleatorios (evalúa [random.randint(1,2)] * 10a [1] * 10, o [2] * 10lo que significa que se obtiene una matriz de todos los 1s o 2s, en lugar de una disposición al azar.
Tzu Li
226

Puedes usar una lista de comprensión :

x = [[foo for i in range(10)] for j in range(10)]
# x is now a 10x10 array of 'foo' (which can depend on i and j if you want)
Adam Rosenfield
fuente
1
dado que el tamaño (10) es el mismo, está bien, si no, el bucle anidado debe ser el primero [foo for j in range (range_of_j)] para i in range (range_of_i)]
Dineshkumar
2
Esta respuesta funciona bien, pero dado que iteramos ipara filas y jcolumnas, creo que debería ser mejor intercambiar iy jen su sintaxis para una mejor comprensión y cambiar el rango a 2 números diferentes.
DragonKnight
139

¡No lo uses [[v]*n]*n, es una trampa!

>>> a = [[0]*3]*3
>>> a
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> a[0][0]=1
>>> a
[[1, 0, 0], [1, 0, 0], [1, 0, 0]]

pero

    t = [ [0]*3 for i in range(3)]

Funciona genial.

Jason CHAN
fuente
26
Sí, yo también caí en esta trampa. Es porque *está copiando el addressdel objeto (lista).
chinuy
1
Votado, ya que esto me atrapó. Para ser más claro, [[0] * col for _ in range(row)].
Abhijit Sarkar
138

De esta manera es más rápido que las comprensiones de la lista anidada

[x[:] for x in [[foo] * 10] * 10]    # for immutable foo!

Aquí hay algunos tiempos de python3, para listas pequeñas y grandes

$python3 -m timeit '[x[:] for x in [[1] * 10] * 10]'
1000000 loops, best of 3: 1.55 usec per loop

$ python3 -m timeit '[[1 for i in range(10)] for j in range(10)]'
100000 loops, best of 3: 6.44 usec per loop

$ python3 -m timeit '[x[:] for x in [[1] * 1000] * 1000]'
100 loops, best of 3: 5.5 msec per loop

$ python3 -m timeit '[[1 for i in range(1000)] for j in range(1000)]'
10 loops, best of 3: 27 msec per loop

Explicación:

[[foo]*10]*10crea una lista del mismo objeto repetido 10 veces. ¡No puedes usar esto, porque modificar un elemento modificará el mismo elemento en cada fila!

x[:]es equivalente list(X)pero es un poco más eficiente ya que evita la búsqueda de nombres. De cualquier manera, crea una copia superficial de cada fila, por lo que ahora todos los elementos son independientes.

Sin fooembargo, todos los elementos son el mismo objeto, por lo que si fooes mutable , no puede usar este esquema., Tendría que usar

import copy
[[copy.deepcopy(foo) for x in range(10)] for y in range(10)]

o suponiendo una clase (o función) Fooque devuelve foos

[[Foo() for x in range(10)] for y in range(10)]
John La Rooy
fuente
44
@ Mike, ¿te perdiste la parte en negrita? si foo es mutable, ninguna de las otras respuestas aquí funciona (a menos que no esté mutando foo)
John La Rooy
1
No puede copiar correctamente objetos arbitrarios con copy.deepcopy. Necesita un plan específico para sus datos si tiene un objeto mutable arbitrario.
Mike Graham
1
Si necesita una velocidad tan alta en un bucle, puede ser hora de usar Cython, tejido o similar ...
james.haggerty
1
@ JohnLaRooy creo que intercambiaste xy y. ¿No debería ser[[copy.deepcopy(foo) for y in range(10)] for x in range(10)]
user3085931
1
@Nils [foo]*10no crea 10 objetos diferentes, pero es fácil pasar por alto la diferencia en el caso de que foo sea inmutable, como un into str.
John La Rooy
62

Para inicializar una matriz bidimensional en Python:

a = [[0 for x in range(columns)] for y in range(rows)]
Vipul
fuente
44
Para inicializar todos los valores a 0, solo use a = [[0 for x in range(columns)] for y in range(rows)].
ZX9
28
[[foo for x in xrange(10)] for y in xrange(10)]
Ignacio Vazquez-Abrams
fuente
1
xrange () se ha eliminado en python3.5
MiaeKim
por qué esto no funciona: [0 * col] * fila. Cuando modifico algún elemento, se replica en otros lugares. Pero no entiendo por qué?
código muncher
Porque eso hace exactamente lo mismo que el código de la pregunta.
Ignacio Vazquez-Abrams
2
@codemuncher La razón por la que [[0] * col] * rowno hace lo que quiere es porque cuando inicializa una lista 2d de esa manera, Python no creará copias distintas de cada fila. En su lugar, iniciará la lista externa con punteros a la misma copia de [0]*col. Cualquier edición que realice en una de las filas se reflejará en las filas restantes, ya que todas apuntan a los mismos datos en la memoria.
Addie
Solo un pensamiento, pero ¿no son buenas todas estas listas para agregar? Es decir. si quiero una lista 2D vacía de dimensión 3 * 6 y deseo agregar al índice [0] [0], [1] [0], [2] [0] y así sucesivamente para completar los 18 elementos, ninguno de estas respuestas funcionarán bien?
mLstudent33
22

Por lo general, cuando desea matrices multidimensionales, no desea una lista de listas, sino más bien una matriz numpy o posiblemente un dict.

Por ejemplo, con numpy harías algo como

import numpy
a = numpy.empty((10, 10))
a.fill(foo)
Mike Graham
fuente
2
Aunque numpyes genial, creo que puede ser un poco exagerado para un principiante.
Esteban Küber
3
numpy proporciona un tipo de matriz multidimensional. Construir una buena matriz multidimensional a partir de listas es posible pero menos útil y más difícil para un principiante que usar numpy. Las listas anidadas son geniales para algunas aplicaciones, pero no suelen ser lo que sería mejor para alguien que desea una matriz 2D.
Mike Graham
1
Después de unos años de hacer ocasionalmente aplicaciones serias de Python, las peculiaridades de las matrices Python estándar parecen justificar simplemente seguir adelante numpy. +1
javadba
12

Puedes hacer exactamente esto:

[[element] * numcols] * numrows

Por ejemplo:

>>> [['a'] *3] * 2
[['a', 'a', 'a'], ['a', 'a', 'a']]

Pero esto tiene un efecto secundario no deseado:

>>> b = [['a']*3]*3
>>> b
[['a', 'a', 'a'], ['a', 'a', 'a'], ['a', 'a', 'a']]
>>> b[1][1]
'a'
>>> b[1][1] = 'b'
>>> b
[['a', 'b', 'a'], ['a', 'b', 'a'], ['a', 'b', 'a']]
Hithwen
fuente
11
En mi experiencia, este efecto "indeseable" es a menudo una fuente de algunos errores lógicos muy malos. En mi opinión, este enfoque debería evitarse, en cambio, la respuesta de @ Vipul es mucho mejor.
Alan Turing
este enfoque funciona bien, ¿por qué en los comentarios que algunas personas refieren es tan malo?
Bravo
1
Debido al efecto secundario no deseado, realmente no se puede tratar como una matriz. Si no necesita alterar el contenido, todo estará bien.
hithwen
9
twod_list = [[foo for _ in range(m)] for _ in range(n)]

para n es el número de filas, y m es el número de columna, y foo es el valor.

Moustafa Saleh
fuente
8

Si se trata de una matriz escasamente poblada, es mejor que utilice un diccionario con una tupla:

dict = {}
key = (a,b)
dict[key] = value
...
btk
fuente
5
t = [ [0]*10 for i in [0]*10]

para cada elemento se [0]*10creará un nuevo .

usuario9269722
fuente
4

Enfoque incorrecto: [[Ninguno * m] * n]

>>> m, n = map(int, raw_input().split())
5 5
>>> x[0][0] = 34
>>> x
[[34, None, None, None, None], [34, None, None, None, None], [34, None, None, None, None], [34, None, None, None, None], [34, None, None, None, None]]
>>> id(x[0][0])
140416461589776
>>> id(x[3][0])
140416461589776

Con este enfoque, Python no permite crear un espacio de direcciones diferente para las columnas externas y dará lugar a un mal comportamiento diferente al esperado.

Enfoque correcto pero con excepción:

y = [[0 for i in range(m)] for j in range(n)]
>>> id(y[0][0]) == id(y[1][0])
False

Es un buen enfoque, pero hay una excepción si establece el valor predeterminado en None

>>> r = [[None for i in range(5)] for j in range(5)]
>>> r
[[None, None, None, None, None], [None, None, None, None, None], [None, None, None, None, None], [None, None, None, None, None], [None, None, None, None, None]]
>>> id(r[0][0]) == id(r[2][0])
True

Establezca su valor predeterminado correctamente utilizando este enfoque.

Absolutamente correcto:

Sigue la respuesta del micrófono de doble bucle .

patilnitina
fuente
3
Matrix={}
for i in range(0,3):
  for j in range(0,3):
    Matrix[i,j] = raw_input("Enter the matrix:")
Sparsh
fuente
1
Si bien este código puede responder la pregunta, proporcionar un contexto adicional con respecto a por qué y / o cómo responde la pregunta mejora su valor a largo plazo.
Ajean
3

Para inicializar un uso de matriz bidimensional: arr = [[]*m for i in range(n)]

Realmente, arr = [[]*m]*n creará una matriz 2D en la que todas las n matrices apuntarán a la misma matriz, por lo que cualquier cambio en el valor de cualquier elemento se reflejará en todas las n listas

Para obtener más información, visite: https://www.geeksforgeeks.org/python-using-2d-arrays-lists-the-right-way/

Abhimanyu
fuente
3

usa el pensamiento más simple para crear esto.

wtod_list = []

y agrega el tamaño:

wtod_list = [[0 for x in xrange(10)] for x in xrange(10)]

o si queremos declarar el tamaño en primer lugar. solo usamos:

   wtod_list = [[0 for x in xrange(10)] for x in xrange(10)]
indi60
fuente
1

Como señalaron @Arnab y @Mike, una matriz no es una lista. Pocas diferencias son 1) las matrices son de tamaño fijo durante la inicialización 2) las matrices normalmente admiten operaciones menores que una lista.

Tal vez una exageración en la mayoría de los casos, pero aquí hay una implementación básica de matriz 2d que aprovecha la implementación de matriz de hardware utilizando python ctypes (bibliotecas c)

import ctypes
class Array:
    def __init__(self,size,foo): #foo is the initial value
        self._size = size
        ArrayType = ctypes.py_object * size
        self._array = ArrayType()
        for i in range(size):
            self._array[i] = foo
    def __getitem__(self,index):
        return self._array[index]
    def __setitem__(self,index,value):
        self._array[index] = value
    def __len__(self):
        return self._size

class TwoDArray:
    def __init__(self,columns,rows,foo):
        self._2dArray = Array(rows,foo)
        for i in range(rows):
            self._2dArray[i] = Array(columns,foo)

    def numRows(self):
        return len(self._2dArray)
    def numCols(self):
        return len((self._2dArray)[0])
    def __getitem__(self,indexTuple):
        row = indexTuple[0]
        col = indexTuple[1]
        assert row >= 0 and row < self.numRows() \
               and col >=0 and col < self.numCols(),\
               "Array script out of range"
        return ((self._2dArray)[row])[col]

if(__name__ == "__main__"):
    twodArray = TwoDArray(4,5,5)#sample input
    print(twodArray[2,3])
Antony Thomas
fuente
1

Lo importante que entendí es: al inicializar una matriz (en cualquier dimensión) Deberíamos dar un valor predeterminado a todas las posiciones de la matriz. Entonces solo se completa la inicialización. Después de eso, podemos cambiar o recibir nuevos valores en cualquier posición de la matriz. El siguiente código me funcionó perfectamente

N=7
F=2

#INITIALIZATION of 7 x 2 array with deafult value as 0
ar=[[0]*F for x in range(N)]

#RECEIVING NEW VALUES TO THE INITIALIZED ARRAY
for i in range(N):
    for j in range(F):
        ar[i][j]=int(input())
print(ar)
Fairoos Ok
fuente
1

Si usa numpy , puede crear fácilmente matrices 2d:

import numpy as np

row = 3
col = 5
num = 10
x = np.full((row, col), num)

X

array([[10, 10, 10, 10, 10],
       [10, 10, 10, 10, 10],
       [10, 10, 10, 10, 10]])
Mehmet Emin Yıldırım
fuente
1
row=5
col=5
[[x]*col for x in [b for b in range(row)]]

Lo anterior le dará una matriz 2D de 5x5

[[0, 0, 0, 0, 0],
 [1, 1, 1, 1, 1],
 [2, 2, 2, 2, 2],
 [3, 3, 3, 3, 3],
 [4, 4, 4, 4, 4]]

Está utilizando la comprensión de la lista anidada. Desglose de la siguiente manera:

[[x]*col for x in [b for b in range(row)]]

[x] * col -> la expresión final que se evalúa
para x en -> x será el valor proporcionado por el iterador
[b para b en el rango (fila)]] -> Iterador.

[b para b en rango (fila)]] esto se evaluará a [0,1,2,3,4] ya que fila = 5,
así que ahora se simplifica a

[[x]*col for x in [0,1,2,3,4]]

Esto evaluará a [[0] * 5 para x en [0,1,2,3,4]] -> con x = 0 1ª iteración
[[1] * 5 para x en [0,1,2, 3,4]] -> con x = 1 2da iteración
[[2] * 5 para x en [0,1,2,3,4]] -> con x = 2 3ra iteración
[[3] * 5 para x en [0,1,2,3,4]] -> con x = 3 4ta iteración
[[4] * 5 para x en [0,1,2,3,4]] -> con x = 4 5ta iteración

Satya
fuente
0

Esto es lo mejor que he encontrado para enseñar a nuevos programadores y sin usar bibliotecas adicionales. Aunque me gustaría algo mejor.

def initialize_twodlist(value):
    list=[]
    for row in range(10):
        list.append([value]*10)
    return list
Paul Vincent Craven
fuente
0

Aquí hay una manera más fácil:

import numpy as np
twoD = np.array([[]*m]*n)

Para inicializar todas las celdas con cualquier valor 'x' use:

twoD = np.array([[x]*m]*n
usuario3650331
fuente
0

A menudo uso este enfoque para inicializar una matriz bidimensional

n=[[int(x) for x in input().split()] for i in range(int(input())]


fuente
0

El patrón general para agregar dimensiones podría extraerse de esta serie:

x = 0
mat1 = []
for i in range(3):
    mat1.append(x)
    x+=1
print(mat1)


x=0
mat2 = []
for i in range(3):
    tmp = []
    for j in range(4):
        tmp.append(x)
        x+=1
    mat2.append(tmp)

print(mat2)


x=0
mat3 = []
for i in range(3):
    tmp = []
    for j in range(4):
        tmp2 = []
        for k in range(5):
            tmp2.append(x)
            x+=1
        tmp.append(tmp2)
    mat3.append(tmp)

print(mat3)
juanfal
fuente
Bienvenido a SO. Esta pregunta ya tiene una respuesta aceptada masivamente votada. A primera vista, esta publicación en realidad no responde la pregunta. Consulte stackoverflow.com/help/how-to-answer para obtener orientación.
Nick
0

Puedes probar esto [[0] * 10] * 10. Esto devolverá la matriz 2D de 10 filas y 10 columnas con valor 0 para cada celda.

ishant
fuente
Esta es esencialmente la misma respuesta que stackoverflow.com/a/25601284/2413201 ...
Armali
2
Esto crea una matriz de 10 punteros a la misma fila. Si lo hace a = [[0]*10]*10y a[0][0] = 1verá que el primer elemento en cada fila ahora es igual a 1
andnik
0

lst = [[0] * m para i en el rango (n)]

inicializar toda la matriz n = filas ym = columnas

HRITIK RAJENDRA AKOLKAR
fuente
¿Puedes formatear el código como código? Sería mucho más legible.
Thomas
0

Otra forma es usar un diccionario para contener una matriz bidimensional.

twoD = {}
twoD[0,0] = 0
print(twoD[0,0]) # ===> prints 0

Esto solo puede contener cualquier valor 1D, 2D y para inicializar esto 0o cualquier otro valor int, use colecciones .

import collections
twoD = collections.defaultdict(int)
print(twoD[0,0]) # ==> prints 0
twoD[1,1] = 1
print(twoD[1,1]) # ==> prints 1
Tej91
fuente
0

Código:

num_rows, num_cols = 4, 2
initial_val = 0
matrix = [[initial_val] * num_cols for _ in range(num_rows)]
print(matrix) 
# [[0, 0], [0, 0], [0, 0], [0, 0]]

initial_val debe ser inmutable

Abhishek Bhatia
fuente
-3
from random import randint
l = []

for i in range(10):
    k=[]
    for j in range(10):
        a= randint(1,100)
        k.append(a)

    l.append(k)




print(l)
print(max(l[2]))

b = []
for i in range(10):
    a = l[i][5]
    b.append(a)

print(min(b))
KANDARP JAYESH SHAH
fuente
44
Agregue un texto que describa lo que hace su código.
whackamadoodle3000
1
Por lo general, es mejor explicar una solución en lugar de solo publicar algunas filas de código anónimo. Puede leer Cómo escribo una buena respuesta , y también Explicar respuestas completamente basadas en código .
Massimiliano Kraus