views:

50

answers:

2

I have some simple code that represents a graph using a square boolean matrix where rows/columns are nodes and true represents an undirected link between two nodes. I am initializing this matrix with False values and then setting the value to True where a link exists.

I believe the way I am initializing the list is causing a single bool instance to be referenced by each cell in a given row. The result is that if I set any cell to True all the other cells in that row also become True.

How should I be initializing my square matrix so that all values are false but none are shared by reference with other cells?

import sys

class Graph(object):
    def __init__(self, nodeCount, links):
        self.matrix = [[False] * nodeCount] * nodeCount
        for l in links:
            self.matrix[l[0]][l[1]] = True

    def __str__(self):
        s = "  "
        for i in range(len(self.matrix)):
            s += str(i) + " "
        s += "\n"
        for r in range(len(self.matrix)):
            s += str(r) + " "
            for c in range(len(self.matrix)):
                s += str(self.matrix[c][r])[0] + " "
            s += "\n"
        return s

g = Graph(5, [(2,3)])
print g

Also, on GIST

+1  A: 
self.matrix = [[False] * nodeCount] * nodeCount

should be something like

self.matrix = [[False] * nodeCount for _ in  range(nodeCount)]
Bwmat
+5  A: 

Actually, you've slightly misunderstood the problem. You believe that the boolean references are shared (this is true, but not important-- booleans are immutable, so sharing references to the same object doesn't mean much). What's happened is that the list references are shared, and that's caused your troubles. Let me show you:

Your code is this

[[False] * nodeCount] * nodeCount

What happens is that you get nodeCount references to a single list with nodeCount references to False. Multiplying a sequene by an integer gives you a sequence with duplicated references-- they're not copies, they're aliases.

>>> x = [False] * 3
>>> y = [x] * 3
>>> y[0] is y[1]
True
>> # your problem
>>> y[0][0] = True
>>> y[1]
[True, False, False]

So in this case, it means you can't change individual rows, because all the rows are the same list, and changing one row changes all.

to fix this, make new lists for each row:

[[False]*nodeCount for _ in xrange(nodeCount)]

example:

>>> y = [[False]*3 for _ in xrange(3)]
>>> y[0] is y[1]
False
>>> y[0][0] = True
>>> y[1]
[False, False, False]
Devin Jeanpierre
you are right, thanks for the detailed explanation
spoon16