views:

354

answers:

8

I'm using a list of lists to store a matrix in python. I tried to initialise a 2x3 Zero matrix as follows.

mat=[[0]*2]*3

However, when I change the value of one of the items in the matrix, it changes the value of that entry in every row, since the id of each row in mat is the same. For example, after assigning

mat[0][0]=1

mat is [[1, 0], [1, 0], [1, 0]].

I know I can create the Zero matrix using a loop as follows,

mat=[[0]*2]
for i in range(1,3):
mat.append([0]*2)

but can anyone show me a more pythonic way?

+7  A: 

Try this:

>>> cols = 6
>>> rows = 3
>>> a = [[0]*cols for _ in [0]*rows]
>>> a
[[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]]
>>> a[0][3] = 2
>>> a
[[0, 0, 0, 2, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]]

This is also discussed in this answer:

>>> lst_2d = [[0] * 3 for i in xrange(3)]
>>> lst_2d
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> lst_2d[0][0] = 5
>>> lst_2d
[[5, 0, 0], [0, 0, 0], [0, 0, 0]]
Paolo Bergantino
Thanks, that's what I was looking for!
Alasdair
+1 - nice stuff. I'm just learning Python, so I greatly appreciate seeing snippets of "pythonic" code.
duffymo
"`[0]*rows`" part is misleading; you're creating a list that is not used in any way except its length. Use either `xrange(n)` or (less likely) `itertools.repeat(None, n)` to do something `n` times in Python.
J.F. Sebastian
+3  A: 

This will work

col = 2
row = 3
[[0] * col for row in xrange(row)]
Nadia Alramli
+2  A: 

What about:

m, n = 2, 3
>>> A = [[0]*m for _ in range(n)]
>>> A
[[0, 0], [0, 0], [0, 0]]
>>> A[0][0] = 1
[[1, 0], [0, 0], [0, 0]]

Aka List comprehension; from the docs:

List comprehensions provide a concise way to create lists 
without resorting to use of     
map(), filter() and/or lambda. 
The resulting list definition tends often to be clearer    
than lists built using those constructs.
The MYYN
+8  A: 

Use a list comprehension:

>>> mat = [[0]*2 for x in xrange(3)]
>>> mat[0][0] = 1
>>> mat
[[1, 0], [0, 0], [0, 0]]

Or, as a function:

def matrix(rows, cols):
    return [[0]*cols for x in xrange(rows)]
Ben Blank
+4  A: 

I use

mat = [[0 for col in range(3)] for row in range(2)]

although depending on what you do with the matrix after you create it, you might take a look at using a NumPy array.

othercriteria
I'm going to explore NumPy at some point, but for my current problem, a list of list is enough.
Alasdair
+1  A: 

See also this question for generalization to an n-levels nested list / n-dimensional matrix.

Sander Evers
+1  A: 

Is there anything itertools can't do? :)

>>> from itertools import repeat,izip
>>> rows=3
>>> cols=6
>>> A=map(list,izip(*[repeat(0,rows*cols)]*cols))
>>> A
[[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]]
>>> A[0][3] = 2
>>> A
[[0, 0, 0, 2, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]]
gnibbler
+4  A: 

This one is faster than the accepted answer!
Using xrange(rows) instead of [0]*rows makes no difference.

>>> from itertools import repeat
>>> rows,cols = 3,6
>>> a=[x[:] for x in repeat([0]*cols,rows)]

A variation that doesn't use itertools and runs around the same speed

>>> a=[x[:] for x in [[0]*cols]*rows]

From ipython:

In [1]: from itertools import repeat

In [2]: rows=cols=10

In [3]: timeit a = [[0]*cols for _ in [0]*rows]
10000 loops, best of 3: 17.8 us per loop

In [4]: timeit a=[x[:] for x in repeat([0]*cols,rows)]
100000 loops, best of 3: 12.7 us per loop

In [5]: rows=cols=100

In [6]: timeit a = [[0]*cols for _ in [0]*rows]
1000 loops, best of 3: 368 us per loop

In [7]: timeit a=[x[:] for x in repeat([0]*cols,rows)]
1000 loops, best of 3: 311 us per loop
gnibbler