2010-08-27 13 views
6

Así que estoy tratando de generar una lista anidada en Python basada en un ancho y una altura. Esto es lo que tengo hasta ahora:Python - Lista dinámica anidada

width = 4 
    height = 5 
    row = [None]*width 
    map = [row]*height 

Ahora, esto obviamente no es del todo correcto. Cuando impresa se ve bien:

[[None, None, None, None], 
[None, None, None, None], 
[None, None, None, None], 
[None, None, None, None], 
[None, None, None, None]] 

Pero intentar asignar un valor a una posición así:

map[2][3] = 'foo' 

me sale:

[[None, None, None, 'foo'], 
[None, None, None, 'foo'], 
[None, None, None, 'foo'], 
[None, None, None, 'foo'], 
[None, None, None, 'foo']] 

Es evidente que esto sucede porque cada sublista es realmente solo haciendo referencia al mismo objeto, hilera, para cambiar uno, los cambia a todos. ¡Así que esto es lo más cercano que tengo!

¿Cómo puedo generar dinámicamente una lista anidada? ¡Gracias!

+0

Aunque no es un duplicado exacto, ver: http://stackoverflow.com/questions/1605024/python-using-the-multiply-operator-to -create-copies-of-objects-in-lists – carl

+2

'map()' es una función incorporada, no es una buena idea anularla. Encuentre otro nombre; si es necesario, puede agregar '_'. –

Respuesta

11

Al hacer [row]*height, termina con el mismo objeto de lista en cada fila. La referencia de matriz row se repite en cada fila, lo que significa que cada fila apunta realmente al mismo objeto de lista. Por lo tanto, modificar una fila en realidad modifica todas las filas.

Eche un vistazo a lo que sucede cuando imprime id() para cada fila. ¡Son todos iguales!

>>> grid = [[None] * width] * height 
>>> [id(row) for row in grid] 
[148014860, 148014860, 148014860, 148014860, 148014860] 

Puede hacer que python genere listas separadas pero idénticas para cada fila mediante el uso de una lista de comprensión. Cuando usa [rowexpr for i in xrange(height)], entonces rowexpr se evaluará una vez por fila. El truco es utilizar una expresión que dará como resultado una lista única cada vez que se evalúa.

Esto va a hacer más sentido si lo ve en acción:

>>> grid = [[None] * width for i in xrange(height)] 
>>> grid[2][3] = 'foo' 
>>> grid 
[[None, None, None, None], 
[None, None, None, None], 
[None, None, None, 'foo'], 
[None, None, None, None], 
[None, None, None, None]] 

Cada vez [None] * width se evalúa que genera una nueva lista.

>>> [id(row) for row in grid] 
[148016172, 148015212, 148016236, 148016108, 148016332] 
0

utilizo algo como esto:

w = 5 
h = 5 

map = [] 

for i in range(h): 
row = [] 
for j in range(w): 
    row.append(None) 
map.append(row) 

print map 

map[2][3] = 'foo' 

print map 
+0

Una lista de comprensión es la __una__ manera correcta de hacer esto. – aaronasterling

+0

Estoy de acuerdo, la comprensión de la lista es más clara, más legible, más 'Ptónica'. Mi manera es solo una forma de resolver el problema y también legible para personas (como yo) que todavía están evolucionando de C a python. – lalli

+0

hacerlo con anidados para bucles no ayuda a usted ni a nadie más a hacer la transición de C a python: simplemente se interpone en el camino. – aaronasterling

Cuestiones relacionadas