Search code examples
pythonfor-loopappendnested-for-loop

Multiplication table function won't append properly


I want the multiplication function to return this when n = 4:

[[1, 2, 3, 4],
 [2, 4, 6, 8],
 [3, 6, 9, 12],
 [4, 8, 12, 16]]

Code:

import numpy

def multiplication_table(n): 
    full_multi = [[]] * n 

    for i in range(n):
        for j in range(n):
            full_multi[i].append( (i+1)*(j+1) )

    list_as_array = numpy.array(full_multi)

    return list_as_array
print(multiplication_table(4))

Instead, this is returned(ignore the format):

[

[ 1  2  3  4  2  4  6  8  3  6  9 12  4  8 12 16]

[ 1  2  3  4  2  4  6  8  3  6  9 12  4  8 12 16]

[ 1  2  3  4  2  4  6  8  3  6  9 12  4  8 12 16]

[ 1  2  3  4  2  4  6  8  3  6  9 12  4  8 12 16]

]

I can't figure out what is wrong. Thx for any help!


Solution

  • Try changing [[] * n] to [[] for _ n range(n)] like this:

    import numpy
    
    def multiplication_table(n): 
        full_multi = [[] for _ n range(n)] 
    
        for i in range(n):
            for j in range(n):
                full_multi[i].append((i+1)*(j+1))
    
        list_as_array = numpy.array(full_multi)
    
        return list_as_array
    print(multiplication_table(4))
    

    This outputs the desired

    [[1, 2, 3, 4],
     [2, 4, 6, 8],
     [3, 6, 9, 12],
     [4, 8, 12, 16]]
    

    The reason the 2 codes are different is because of how copying (in this case multiplying lists) works. By doing [[] * n], you don't actually create n different lists but simply create n references of the [] list.

    If we debug the code by adding a print statement after full_multi[i].append( (i+1)*(j+1)) to print the value of full_multi we can see this behavior:

    [[1], [1], [1], [1], [1]]
    [[1, 2], [1, 2], [1, 2], [1, 2], [1, 2]]
    ...
    

    Adding a value to the first list also makes it appear in the rest because they all reference the same data. However, the for loop method actually creates n separate lists.

    See https://www.geeksforgeeks.org/copy-python-deep-copy-shallow-copy/ for more.

    When copying lists (or any non-primitive data type) in Python (or most languages), you don't actually duplicate the data but simply create a new reference.

    a = 5
    b = a  # for primitive data like integers, the value 5 is copied over
    
    a = []
    b = a  # only the reference to the list stored in 'a' is copied
    
    a.append(5)
    print(a, b)  # will both be the same value since they are the same list, just referenced by 2 different variables
    

    If you'd like to actually copy the list itself, you must do something like:

    a = []
    b = a.copy()  # copies the list, not just the reference
    
    a.append(5)
    print(a, b)  # will both be different