1

I am seeing a very unusual behavior in python.. Kindly let me know what am i doing wrong!!

bc = [[0]*(n+1)]*(n+1)

for i in range(n+1):
    bc[i][i] = 1

print (bc)        

Output

[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]

I am trying to initialize the diagonal elements of two dimensional array to 1, but it is initializing all the elements with 1. I think I am doing something wrong with accessing two dimensional Array..

Also, kindly let me know how can I use two loops to access all the elements of two dimensional array.. my next step..

Thanks.

AlgoGeek
  • 91
  • 2
  • 8
  • possible duplicate of [Python list multiplication: \[\[...\]\]*3 makes 3 lists which mirror each other when modified](http://stackoverflow.com/questions/6688223/python-list-multiplication-3-makes-3-lists-which-mirror-each-other-when) – Ignacio Vazquez-Abrams Jul 31 '11 at 08:05
  • @Ignacio the fundamental problem is the same, but it's entirely understandable that the OP wouldn't realize that's what's causing it. – Karl Knechtel Jul 31 '11 at 09:08

3 Answers3

6

Your array is initialized incorrectly. The correct way to initialize a 2d array is this:

bc = [[0 for i in xrange(n + 1)] for i in xrange(n + 1)]

It's a common mistake, but the * operator copies the pointer to an list rather than copying the list, so while it looks like you have a 2d list, you actually have a 1d list of pointers to the same list.

Charles Ma
  • 47,141
  • 22
  • 87
  • 101
  • 1
    "copies the pointer to" is awkward terminology that doesn't fit Python. More accurately, Python has *reference semantics* for both values and variables, and never copies by value implicitly; multiplication produces a list that stores multiple references to the same original value, just as it stored a reference in the first place. – Karl Knechtel Jul 31 '11 at 09:11
3

the problem is that each array in your array is the same array in memory. you need a new array each time. the [[0]]*6 will for example make 6 of the same arrays in an array, editing one of them will update the other ones.

e.g.

>>> x=[1]
>>> y=x
>>> x.append(3)
>>> x
[1, 3]
>>> y
[1, 3]
>>> z=[x]*3
>>> x.append(6)
>>> z
[[1, 3, 4, 6], [1, 3, 4, 6], [1, 3, 4, 6]]

here is a fix by simply editing bc to be n+1 different arrays:

n=4
bc = [[0]*(n+1) for i in range(n+1)]

for i in range(n+1):
    bc[i][i] = 1

print (bc)

[[1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1]]
Rusty Rob
  • 16,489
  • 8
  • 100
  • 116
  • 1
    No worries. You could go [[0]*i+[1]+[0]*(n-i) for i in range(n)] – Rusty Rob Jul 31 '11 at 08:14
  • Note that in the inner arrays, to start, the list actually stores several copies of the same "0" object :) but this does not cause a problem, because mathematical operations - **even things like `+=`** - replace the object rather than modifying it: Python's built-in `int`s are immutable. – Karl Knechtel Jul 31 '11 at 09:12
0

Try this one:

bc = [[0 for i in range(n+1)] for j in range(n+1)]

In your example you have only one (!) instance of [0] which is referenced multiple times. So if you change that instance, all references are changed.

Achim
  • 15,415
  • 15
  • 80
  • 144
  • 1
    More to the point, he has one instance of [0, 0, 0...] (n + 1 zeroes). And within that instance, the 0s are all the same object, not that it matters. – Karl Knechtel Jul 31 '11 at 09:14