0

This really, really messed with me today. This is the most minimum working example I could get:

array = [ 1, 2, 1, 3, 4 ]                                                          
n = 3                                                                              
strips = [[0] * n] * n                                                                                                                               
mSum = 7                                                                           
j = 0                                                                              
                                                                                   
strips[0][j] = mSum                                                                
                                                                                   
print(f'before strips[0]: {strips[0][0]}')                                         
                                                                                   
for i in range(1, len(array) - n + 1):                                             
    mSum += array[i + n - 1] - array[i - 1]                                        
    strips[i][j] = mSum                                                            
    print(f'strips[{i}][{j}]: {strips[i][j]}')                                     
                                                                                   
print(f'after strips[0]: {strips[0][0]}')     

If strips is not a nested-list, the error doesn't occur. Here is the output:

before strips[0][0]: 7
strips[1][0]: 9
strips[2][0]: 11
after strips[0][0]: 11

Why is strips[0][0] different before and after the loop (where it does not get modified)? The only thing I can think of is that it's somehow connected to mSum.

The same code in a language like C++ does not have this issue.

user129393192
  • 797
  • 1
  • 8
  • You don't have different inner lists. It's 3 times the same list. An easier example: `strips = [[0] * 3] * 3; strips[0][0] = 1; print(strips)`. – Matthias Aug 09 '23 at 22:12

1 Answers1

1

From Common Sequence Operations, s * n is equivalent to adding s to itself n times. You created a list with n zeros in it, then added that list to an outer list n times. Now you have a bunch of references to a single list.

Python's list would be like a C++ std::list, not something like int test[10][10];.

In your case, you are doing the equivalent of

tmp = [0] * n
strips = tmp * n

that tmp list wouldn't have any idea how its values were created so it wouldn't have any ability to create new ones. Instead it just duplicates.

You can get what you want with

strips = [[0] * n] for _ in range(n)]

This still has the problem where [0] * n just adds new references to 0 to fill the array. This is not a problem for any immutable type because, well, they can't be changed, so who cares if there are a bunch of references to them. It would be a problem if you were using some other mutable type.

tdelaney
  • 73,364
  • 6
  • 83
  • 116
  • Thanks. Very clear. I'll have to start thinking of everything as a reference in Python. – user129393192 Aug 09 '23 at 22:28
  • @user129393192. Yeah, python doesn't have any primary data types. If you want a dense array of integers instead of the more expensive `int` objects, you can use packages such as numpy and pandas. – tdelaney Aug 09 '23 at 22:41
  • How do you mean? Isn't `int` built-in? I understand it's immutable and an object with an `id` and `type` and all that comes with it. – user129393192 Aug 09 '23 at 23:52
  • @user129393192 - Its builtin, but its not a primary type - meaning that its not just a hardware level integer. Its a class and can be inherited. Operations go though method calls. In C++, operations on integers compile to assembler. – tdelaney Aug 10 '23 at 00:50