Liky
Liky

Reputation: 1247

2 dimensional arrays with dictionary in each cell

I have a little issue with the following code. I first create a 2 dimensional array that I fill in with dictionaries (the same dictionary for each cell actually). Now, when I update a cell changing of of the value in the dictionary, all the dictionaries in the whole array are changed and not only array[0][0]. See the code below:

dict_cell = {'item1': 20, 'item2': 25}
width = 2
height = 2
array = []
for i in range(height):
    row=[]
    for j in range(width):
        row.append(dict_cell)
    array.append(row)
array[0][0]['item1'] =2
print array

I get the following output:

[[{'item2': 25, 'item1': 2}, 
  {'item2': 25, 'item1': 2}], 
 [{'item2': 25, 'item1': 2}, 
  {'item2': 25, 'item1': 2}]]

when I would like to have:

[[{'item2': 25, 'item1': 2}, 
  {'item2': 25, 'item1': 20}], 
 [{'item2': 25, 'item1': 20}, 
  {'item2': 25, 'item1': 20}]]

Any suggestions? Note: I can not use numpy.

Upvotes: 1

Views: 5936

Answers (2)

Aaditya Ura
Aaditya Ura

Reputation: 12669

Let's explore your issue by a little example:

so suppose you have a list:

a=['something']

And there is also a second list which contains:

list_1=[a,a,a]

So when you do:

a[0]="something_else"

what do you think what is the output of list_1 ?

Let's check:

a=['something']
list_1=[a,a,a]


a[0]="something_else"
print(list_1)

output:

[['something_else'], ['something_else'], ['something_else']]

Because in python variable doesn't store the value , variable are just referece to the object and object store the value so in list_1 all the variable are pointing to the same object:

checking:

for i in list_1:
    print(id(i))

output:

4329477768
4329477768
4329477768

In your case:

dict_cell = {'item1': 20, 'item2': 25}
width = 2
height = 2
array = []
for i in range(height):
    row=[]
    for j in range(width):
        row.append(dict_cell)
    array.append(row)
array[0][0]['item1'] =2



for item in array:
    if isinstance(item,list):
        for sub_item in item:
            print(id(sub_item))

output:

4302653768
4302653768
4302653768
4302653768

so as you can see all variable in the list are pointing to the same dict so if you change anything to one , it will affect the main dict.

so when you do :

array[0][0]['item1'] =2

you are not only modifying array's dict , you are actually modifying original dict too let's check:

dict_cell = {'item1': 20, 'item2': 25}
width = 2
height = 2
array = []
print("before modification {}".format(dict_cell))
for i in range(height):
    row=[]
    for j in range(width):
        row.append(dict_cell)
    array.append(row)
array[0][0]['item1'] =2

print("after  modification {}".format(dict_cell))

output:

before modification {'item1': 20, 'item2': 25}
after  modification {'item1': 2, 'item2': 25}

Ok i got the issue but what is the solution?

Try deepcopy:

from copy import deepcopy
dict_cell = {'item1': 20, 'item2': 25}
width = 2
height = 2
array = []
for i in range(height):
    row=[]
    for j in range(width):
        row.append(deepcopy(dict_cell))
    array.append(row)
array[0][0]['item1'] =2
print(array)

output:

[[{'item1': 2, 'item2': 25}, {'item1': 20, 'item2': 25}], [{'item1': 20, 'item2': 25}, {'item1': 20, 'item2': 25}]]

why deepcopy why not copy ?

suppose you have dict like this:

dict_cell = {'item1': [20,34], 'item2': [25,9]}

you run your code with this dict_cell and you got the output:

[[{'item2': [25, 9], 'item1': 2}, {'item2': [25, 9], 'item1': [20, 34]}], [{'item2': [25, 9], 'item1': [20, 34]}, {'item2': [25, 9], 'item1': [20, 34]}]]

Now let's try to change the original dict values :

dict_cell = {'item1': [20,34], 'item2': [25,9]}
width = 2
height = 2
array = []
for i in range(height):
    row=[]
    for j in range(width):
        row.append(dict_cell.copy())
    array.append(row)
array[0][0]['item1'] =2


for key,value in dict_cell.items():
    value[0]='changed'

print(array,'\n')

output:

[[{'item1': 2, 'item2': ['changed', 9]}, {'item1': ['changed', 34], 'item2': ['changed', 9]}], [{'item1': ['changed', 34], 'item2': ['changed', 9]}, {'item1': ['changed', 34], 'item2': ['changed', 9]}]] 

we modifed the orional dict but it changed the content in array list's dict because that is shallow copy of dict. it copied the dict but didn't copy the nested list.

Solution :

Use deepcopy.

Upvotes: 4

dsm
dsm

Reputation: 2253

The way python works is that when you're appending dict_cell to row, it adds a pointer to the dictionary. So, in effect, you're basically linking the same dictionary a bunch of times! It's thus unsurprising that all dictionaries are changing when you modify one of the entries.

The simplest change to fix this is to directly create multiple dictionaries, using dict_cell as the template. Replace your append in the for loop with this:

    row.append(dict_cell.copy())

Upvotes: 4

Related Questions