¿Cómo inicializar una matriz bidimensional en Python?

Resuelto thepandaatemyface asked hace 14 años • 31 respuestas

Estoy comenzando con Python y estoy tratando de usar una lista bidimensional, que inicialmente lleno con la misma variable en todos los lugares. 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 parece una solución alternativa. ¿Existe una forma más fácil/corta/elegante de hacer esto?

thepandaatemyface avatar Mar 08 '10 00:03 thepandaatemyface
Aceptado

Para inicializar una lista bidimensional en Python, use

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

¡Pero 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]]
Jason CHAN avatar Jun 06 '2017 06:06 Jason CHAN

Un patrón que aparecía a menudo en Python era

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

lo que ayudó a motivar la introducción de listas por comprensión, que convierten ese fragmento en

bar = [SOME_EXPRESSION for item in some_iterable]

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

Tu 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 avatar Mar 07 '2010 17:03 Mike Graham

Puedes usar una lista por 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 avatar Mar 07 '2010 17:03 Adam Rosenfield

De esta manera es más rápido que las listas por comprensión anidadas.

[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 simplemente usar esto, porque modificar un elemento modificará ese mismo elemento en cada fila!

x[:]es equivalente a 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 embargo, todos los elementos son el mismo fooobjeto, por lo que si fooes mutable , no puedes usar este esquema, tendrías que usar

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

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

[[Foo() for x in range(10)] for y in range(10)]
John La Rooy avatar Mar 07 '2010 22:03 John La Rooy

Para inicializar una matriz bidimensional en Python:

a = [[0 for x in range(columns)] for y in range(rows)]
Vipul avatar Dec 11 '2013 18:12 Vipul