'List operation, keeping track of old list

After I apply an operation to a list, I would like to get access to both the modified list and the original one. Somehow I am not able to.

In the following code snippet, I define two functions with which I modify the original list. Afterwards, I get my values from a class and apply the transformation.

def get_min_by_col(li, col):                          # get minimum from list
    return min(li, key=lambda x: x[col - 1])[col - 1]

def hashCluster(coords):                              # transform to origin
    min_row = get_min_by_col(coords,0)
    min_col = get_min_by_col(coords,1)
    for pix in coords:
        pix[1] = pix[1] - min_row
        pix[0] = pix[0] - min_col
    return (coords)


pixCoords = hashCoords = originalPixCoords = []       # making sure they are empty
for j in dm.getPixelsForCluster(dm.clusters[i]):
    pixCoords.append([j['m_column'], j['m_row']])     # getting some values from a class -- ex:   [[613, 265], [613, 266]]   or    [[615, 341], [615, 342], [616, 341], [616, 342]] 
originalPixCoords = pixCoords.copy()                  # just to be safe, I make a copy of the original list
print ('Original : ', originalPixCoords)              
hashCoords = hashCluster(pixCoords)                   # apply transformation
print ('Modified : ', hashCoords)
print ('Original : ', originalPixCoords)              # should get the original list

Some results [Jupyter Notebook]:

Original :  [[607, 268]]
Modified :  [[0, 0]]
Original :  [[0, 0]]

Original :  [[602, 264], [603, 264]]
Modified :  [[0, 0], [1, 0]]
Original :  [[0, 0], [1, 0]]

Original :  [[613, 265], [613, 266]]
Modified :  [[0, 0], [0, 1]]
Original :  [[0, 0], [0, 1]]

Is the function hashCluster able to modify the new list as well? Even after the .copy()?

What am I doing wrong? My goal is to have access to both the original and modified lists, with as less operations and copies of lists as possible (since I am looping over a very large document).



Solution 1:[1]

use

import copy
OriginalPixCoords= copy.deepcopy(pixCoords)

Solution 2:[2]

What you're using is a shallow copy. It effectively means you created a new list and just pointed to the old memory spaces. Meaning if those object got modified, your new list will still reflect those updates since they occurred in the same memory space.

>>> # Shallow Copy
>>> mylist = []
>>> mylist.append({"key": "original"})
>>> mynewlist = mylist.copy()
>>> mynewlist
[{'key': 'original'}]
>>> mylist[0]["key"] = "new value"
>>> mylist
[{'key': 'new value'}]
>>> mynewlist
[{'key': 'new value'}]

>>> # Now Deep Copy
>>> mylist = []
>>> mylist.append({"key": "original"})
>>> from copy import deepcopy
>>> mynewlist = deepcopy(mylist)
>>> mynewlist
[{'key': 'original'}]
>>> mylist[0]["key"] = "new value"
>>> mylist
[{'key': 'new value'}]
>>> mynewlist
[{'key': 'original'}]

Another similar question: What is the difference between shallow copy, deepcopy and normal assignment operation?

Solution 3:[3]

Settings multiple variables equal to the same value is the equivalent of a pointer in Python.

Check this out

a = b = [1,2,3]
a == b # True
a is b    # True (same memory location)
b[1] = 3
print(b)  # [1,3,3]
print(a)  #[1,3,3]

Right now, you are creating shallow copies. If you need both copies (with different values and data history), you can simply assign the variables in the following manner:

import copy

original = data
original_copy = copy.deepcopy(data)
original_copy == original == data # True
original_copy is original   # False
original_copy[0] = 4
original_copy == original  # False

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Igor Rivin
Solution 2 Kamori
Solution 3 justahuman