Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Looping through a list of lists

Tags:

python

list

I am new to programming and I have this basic problem I cannot fix. I simplified it as much as possible. In this simplified version, I am iterating through an empty list. I just want to store the indices in the "symmetric matrix":

n = 2
B = [[None] * n] * n
print B, "\n"
for i in range(n):
    for j in range(n):
        B[i][j] = [i, j]
        print B

Initially, the list looks like this:

[[None, None], [None, None]] 

After looping trough, I would expect the print-out to be:

[[[0, 0], None], [None, None]]
[[[0, 0], [0, 1]], [None, None]]
[[[1, 0], [0, 1]], [[1, 0], None]]
[[[1, 0], [1, 1]], [[1, 0], [1, 1]]]

Instead, I get this:

[[[0, 0], None], [[0, 0], None]]
[[[0, 0], [0, 1]], [[0, 0], [0, 1]]]
[[[1, 0], [0, 1]], [[1, 0], [0, 1]]]
[[[1, 0], [1, 1]], [[1, 0], [1, 1]]]

What am I missing? Thanks for helping out...

like image 872
Mitya Stiglitz Avatar asked Feb 15 '23 23:02

Mitya Stiglitz


2 Answers

What you need instead of the current way you're defining B is n "fresh" instances of the sublist:

B = [[None] * n for _ in range(n)]

which is equivalent to but shorter and (for a Pythonista) more readable than:

B = []
for _ in range(n):
    B.append([None] * n)

This is because lists in Python are not values but objects; i.e. they are not copied by default. For example:

>>> a = []
>>> b = [a, a]  # list of 2 items, both pointing to the same list instance
>>> b[0].append(1)  # b[0] refers to the same list instance also referenced by a
>>> print b
[[1], [1]]

whereas:

>>> b = [[], []]  # list of 2 distinct sublists
>>> b[0].append(1)
>>> print b
[[1], []]

If you apply that knowledge to

B = [[None] * n] * n

you'll see there's an error in the construction—you're creating a list that contains another list of n None values; you're then "upsizing" the list to contain n of such lists; however, the same list instance will be used just like in the above, more trivial examples.

P.S. more accurately, everything in Python is an object not a value, except in cases where the object is immutable, such as ints and floats and strs etc, it is as if they are values and are always copied—this is because if an object is immutable, you might as well pretend a new reference to it is a new copy of it, because it looks the same and cannot be modified.

like image 168
Erik Kaplun Avatar answered Feb 17 '23 12:02

Erik Kaplun


Your initialization creates two references to the same list:

n=2
B=[[None]*n]*n
for x in B:
     print id(x)

Output:

4534759576
4534759576
like image 21
tback Avatar answered Feb 17 '23 12:02

tback