generating a grid in a function
We made a little script in computer science class for finding the shortest path through a grid of nodes, some interlinked, some not. The griddata is stored in a way that doesn't require to define any new classes, namely in a nested list. For n nodes, the list should have n elements, each being a list with n elements.
grid[a][b]
should return the distance from node a to node b, and 0 if the nodes aren't connected or if a and b references to the same node.
for example the list [[0,2,2],[2,0,2],[2,2,0]]
would define a grid with 3 nodes, each with a distance of 2 from each other.
Here is the script I wrote that should define such a grid by requesting individual distances from the user:
def makegrid(nodes):
res=[[0]*nodes]*nodes
for i in range(nod开发者_高级运维es):
for j in range(nodes):
if res[i][j]==0 and not i==j:
x=raw_input('distance node %d zu node %d: ' % (i,j))
if x:
res[i][j]=res[j][i]=int(x)
else:
res[i][j]=res[j][i]=None
for i in range(nodes):
for j in range(nodes):
if res[i][j] is None:
res[i][j]=0
return res
My problem ist that the function isn't quite doing what I intended it to do, and I can't seem to work out why. What it actually does is only running through the requests for the first node, and somehow it does to all the sublists what it should only do to the first (and ignoring that the first element should not be changed).
Can anyone help me figure it out?
res=[[0]*nodes]*nodes
probably doesn't do what you think it does:
>>> nodes = 3
>>> res=[[0]*nodes]*nodes
>>> res
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> res[0][0] = 'echo'
>>> res
[['echo', 0, 0], ['echo', 0, 0], ['echo', 0, 0]]
Instead of making three separate lists [0,0,0], it gives you three references to the same list:
>>> id(res[0]), id(res[1]), id(res[2])
(4299671960, 4299671960, 4299671960)
Try
res=[[0]*nodes for i in range(nodes)]
instead, and read, e.g., Multiply operator applied to list(data structure) to understand why the difference in mutability of integers and lists explains why the [0]*nodes part seems to behave like you'd expect -- i.e. why the above answer has multiple copies of ['echo', 0, 0], not ['echo', 'echo', 'echo'] -- even though the final "*nodes" doesn't.
I fell for that trap, too. List multiplication does not do what you expect it to. Check out this thread.
Easy workaround using list comprehension instead:
# res=[[0]*nodes]*nodes
res = [[0 for j in range(nodes)] for i in range(nodes)]
精彩评论