pythonlistcopysliceimmutablelist

How to copy a list to another variable and leave this variable immutable?


I've maid an algorithm that reverse the diagonals of an array. I'm trying to copy the list a to b immutable.

I tried to use "slices" (b = a[:]), list comprehension and b = a.copy() but the only one that worked was b = copy.deepcopy(a). Are there other ways to get the copy?

import copy
a = [[1,2,3],[4,5,6],[7,8,9]]
b = copy.deepcopy(a)
d = b
c = []

h = len(a[0])-1
x_ptrocar = []

for i in range(len(a)-1):
    if i == h:
        break
    else:
        x_ptrocar.extend([[i,i,h,h],[i,h,h,i],[h,h,i,i],[h,i,i,h]])
        h -=1
for l in range(len(x_ptrocar)):
    for m in range(0,4):
        y_original = x_ptrocar[l][3]
        y_ptrocar = x_ptrocar[l][1]
        x_original = x_ptrocar[l][2]
        x_ptrocarr = x_ptrocar[l][0]
        a[x_original][y_original]=b[x_ptrocarr][y_ptrocar]
print(a)

I expect the output of [[1,2,3],[4,5,6],[7,8,9]] to be [[9,2,7], [4,5,6],[3,8,1]], and it's working for copy.deepcopy, but not for any other method I can find.


Solution

  • copy.deepcopy is overkill for this, pulling in a module and adding function overhead. Since you have a list of lists, making a copy of the outer list with b = a[:] isn't sufficient because the inner lists in both a and b point to identical objects.

    You can use a list comprehension as follows:

    b = [x[:] for x in a]
    

    This takes a slice of each list in a, creating a new copy of each sublist without aliasing.


    Incidentally, the logic can be simplified somewhat--walk towards the center of the matrix, swapping the top-left/bottom-right and top-right/bottom-left cells along the way:

    def reverse_diagonals(m):
        m = [x[:] for x in m]
    
        for i in range(len(m) // 2):
            m[i][i], m[-i-1][-i-1] = m[-i-1][-i-1], m[i][i]
            m[i][-i-1], m[-i-1][i] = m[-i-1][i], m[i][-i-1]
    
        return m
    

    This assumes a nxn matrix.