2

I want to create a diagonal matrix below's the code in python 2.7

def diag(steps):
    '''
    steps : a positive integer
    '''
    matrix = [[0]*steps]*steps    # matrix of the order step x step
    for i in range(steps + 1):
        matrix[i][i] = i + 1    # i'th' element of 'i'th row
    return matrix

For eg: if step = 3, I should get [ [1, 0, 0], [0, 2, 0], [0, 0, 3] ]. But I'm getting [ [1, 2, 3], [1, 2, 3], [1, 2, 3] ] Can anyone help me with this bug and please tell what's wrong with my logic?

pltrdy
  • 2,069
  • 1
  • 11
  • 29
Stetson
  • 23
  • 4
  • Possible duplicate of [Python list of lists, changes reflected across sublists unexpectedly](http://stackoverflow.com/questions/240178/python-list-of-lists-changes-reflected-across-sublists-unexpectedly) – Łukasz Rogalski Mar 09 '16 at 15:16
  • you should validate an anwser – pltrdy Mar 15 '16 at 10:48

2 Answers2

1

By multiplying an array you don't create a matrix with three different arrays. You create multiple references to the same array.

Example:

> a = [2,2,2]
> b = [a]*3
> print b
[[2, 2, 2], [2, 2, 2], [2, 2, 2]]
> a[1] = 4
> print b
[[2, 4, 2], [2, 4, 2], [2, 4, 2]]
> b[0][0] = 8
> print b 
[[8, 4, 2], [8, 4, 2], [8, 4, 2]]

You see? Every first element in every 3-array is now 8, not only b[0][0]. That is because they all are the same object.

You have to change

matrix = [[0]*steps]*steps 

to

# probably not the best pythonic way but it works
matrix = [[0 for x in range(steps)] for x in range(steps)]
Psytho
  • 3,313
  • 2
  • 19
  • 27
0

1) For convenience, you may consider using numpy which allows to work in a more 'mathematical' way instead of python's list. In your case you may want to look at numpy.diag(vector) which create a len(vector)xlen(vector) matrix where matrix[i][i] = vector[i]

For your need, using numpy you can do:

import numpy as np
matrix = np.diag( list(range(1, steps+1))

And thats all

2) To anwser your precise question (in case you can't use numpy for some reason) you could make it short:

def diag(steps):
    matrix = [ [0]*i+[i+1]+[0]*(steps-i-1) for i in range(steps) ]
    return matrix
pltrdy
  • 2,069
  • 1
  • 11
  • 29