1

I know that list aliasing is an issue in Python, but I can't figure out a way around it.

def zeros(A):
    new_mat = A
    for i in range(len(A)):
        for j in range(len(A[i])):
            if A[i][j]==0:
                for b in range(len(A)):
                    new_mat[b][j] = 0
            else:
                new_mat[i][j] = A[i][j]
    return A

Even though I don't change the values of A at all, when I return A, it is still modified:

>>> Matrix = [[1,2,3],[5,0,78],[7,3,45]]
>>> zeros(Matrix)
[[1, 0, 3], [5, 0, 78], [7, 0, 45]]

Is this list aliasing? If so, how do you modify elements of a 2D array without aliasing occurring? Thanks so muhc <3.

4 Answers 4

3

new_mat = A does not create a new matrix. You have merely given a new name to the object you also knew as A. If it's a list of lists of numbers, you might want to use copy.deepcopy to create a full copy, and if it's a numpy array you can use the copy method.

Sign up to request clarification or add additional context in comments.

Comments

1
new_mat = A[:]

This creates a copy of the list instead of just referencing it. Give it a try.

[:] just specifies a slice from beginning to end. You could have [1:] and it would be from element 1 to the end, or [1:4] and it would be element 1 to 4, for instance. Check out list slicing regarding that.

2 Comments

This wouldn't solve the problem if A contained more complex objects than integers. In fact in this case it will create a new outer list, but alias the inner lists. You need to deep copy. For slices, you'd need new_mat = [sl[:] for sl in A] to copy the inner lists, but you'd still run into aliasing if the values in the inner lists are not immutable.
You are correct. In that case, the copy module is what he needs.
1

This might help someone else. just do this.

import copy

def zeros(A):
    new_mat = copy.deepcopy(A)

Comments

1

QUICK EXPLANATION

If you want A to be the original matrix your function should be like this. Just use np.copy() function

def zeros(A):
    new_mat = np.copy(A) #JUST COPY IT WITH np.copy() function
    for i in range(len(A)):
        for j in range(len(A[i])):
            if A[i][j]==0:
                for b in range(len(A)):
                    new_mat[b][j] = 0
            else:
                new_mat[i][j] = A[i][j]
    return A

THOROUGH EXPLANATION

Let's say we don't want numpy ndarray a to have aliasing. For example, we want to prevent a to change any of its values when we take (for example) a slice of it, we assign this slice to b and then we modify one element of b. We want to AVOID this:

import numpy as np
a = np.array([[1,2,3],[4,5,6],[7,8,9]])
b = a[0]
b[2] = 50
a
Out[]: 
array([[ 1,  2, 50],
       [ 4,  5,  6],
       [ 7,  8,  9]])

Now you might think that treating a numpy-ndarray object as if it was a list object might solve our problem. But it DOES NOT WORK either:

%reset #delete all previous variables
a = np.array([[1,2,3],[4,5,6],[7,8,9]])
b = a[:][0] #this is how you would have copied a slice of "a" if it was a list
b[2] = 50
a
Out[]: 
array([[ 1,  2, 50], #problem persists
       [ 4,  5,  6],
       [ 7,  8,  9]])

The problem gets solved, in this case, if you think of numpy arrays as different objects than python lists. In order to copy numpy arrays you can't do copy = name_array_to_be_copied[:], but copy = np.copy(name_array_to_be_copied). Therefore, this would solve our aliasing problem:

%reset #delete all previous variables
import numpy as np
a = np.array([[1,2,3],[4,5,6],[7,8,9]])
b = np.copy(a)[0] #this is how you copy numpy ndarrays. Calling np.copy() function
b[2] = 50
a
Out[]: 
array([[1, 2, 3], #problem solved
       [4, 5, 6],
       [7, 8, 9]])

P.S. Watch out with the zeros() function. Even after fixing the aliasing issue, your function does not convert to 0 the columns in the new_matrix who have at least one zero in the same column for the matrix A (this is what I think you wanted to acomplish by seeing the incorrectly reported output of your function [[1, 0, 3], [5, 0, 78], [7, 0, 45]], since it actually yields [[1,0,3],[5,0,78],[7,3,45]]). If you want that you can try this:

def zeros_2(A):
    new_mat = np.copy(A)
    for i in range(len(A[0])): #I assume each row has same length.
        if 0 in new_mat[:,i]:
            new_mat[:,i] = 0
    print(new_mat)
    return A

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.