11

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?

Alasdair
  • 298,606
  • 55
  • 578
  • 516

8 Answers8

9

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
  • 54,908
  • 28
  • 127
  • 156
8

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]]
Community
  • 1
  • 1
Paolo Bergantino
  • 480,997
  • 81
  • 517
  • 436
  • +1 - nice stuff. I'm just learning Python, so I greatly appreciate seeing snippets of "pythonic" code. – duffymo May 28 '09 at 21:04
  • 7
    "`[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. – jfs Dec 09 '09 at 22:25
7

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
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
4

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
  • 431
  • 2
  • 4
3

This will work

col = 2
row = 3
[[0] * col for row in xrange(row)]
Nadia Alramli
  • 111,714
  • 37
  • 173
  • 152
2

If the sizes involved are really only 2 and 3,

mat = [[0, 0], [0, 0], [0, 0]]

is easily best and hasn't been mentioned yet.

RemcoGerlich
  • 30,470
  • 6
  • 61
  • 79
2

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.
miku
  • 181,842
  • 47
  • 306
  • 310
1

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]]
John La Rooy
  • 295,403
  • 53
  • 369
  • 502