GDScript and iteration through dictionnaries

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By snk

Hi,
I wrote something like this :

var dict = { 
0: {"value1":"x"}, 
1: {"value1":"x"}, 
2: {"value1":"x"}, 
3: {"value1":"y"}, 
4: {"value1":"y"}, 
5: {"value1":"y"}
}

var list = [ [1,2,3], [4,5,6] ]

func write_in_dictionnary(dict, list):
        var local_dict = dict
        var i_x = 0
        var i_y = 0
	for key in local_dict:
		if local_dict[key]["value1"] == "x":
			local_dict[key]["value2"] = list[0][i_x]
			i_x += 1
		else:
			local_dict[key]["value2"] = list[1][i_y]
			i_y += 1
	return local_dict

what I should get :
local_dict
{
0: {“value1”:“x”, “value2”: 1},
1: {“value1”:“x”, “value2”: 2},
2: {“value1”:“x”, “value2”: 3},
3: {“value1”:“y”, “value2”: 4},
4: {“value1”:“y”, “value2”: 5},
5: {“value1”:“y”, “value2”: 6}
}

what I get :
local_dict :
{
0: {“value1”:“x”, “value2”: 3},
1: {“value1”:“x”, “value2”: 3},
2: {“value1”:“x”, “value2”: 3},
3: {“value1”:“y”, “value2”: 6},
4: {“value1”:“y”, “value2”: 6},
5: {“value1”:“y”, “value2”: 6}
}

I also tried like this :

func write_in_dictionnary(dict, list):
        var local_dict = dict
        var i_x = 0
        var i_y = 0
	for key in dict:
            nested_dict = local_dict[key]
		if nested_dict["value1"] == "x":
			nested_dict["value2"] = list[0][i_x]
                    local_dict[key] = nested_dict
			i_x += 1
		else:
			nested_dict[key]["value2"] = list[1][i_y]
                    local_dict[key] = nested_dict
			i_y += 1
	return local_dict

I got the same result.

I even tried something like this for testing :

func write_in_dictionnary(dict, list):
        var local_dict = dict
	for key in dict:
		if local_dict[key]["value1"] == "x":
			local_dict[key]["value2"] = key
		else:
			local_dict[key]["value2"] = key
	return local_dict

which should give me :
local_dict
{
0: {“value1”:“x”, “value2”: 0},
1: {“value1”:“x”, “value2”: 1},
2: {“value1”:“x”, “value2”: 2},
3: {“value1”:“y”, “value2”: 3},
4: {“value1”:“y”, “value2”: 4},
5: {“value1”:“y”, “value2”: 5}
}

but I still get :
local_dict :
{
0: {“value1”:“x”, “value2”: 2},
1: {“value1”:“x”, “value2”: 2},
2: {“value1”:“x”, “value2”: 2},
3: {“value1”:“y”, “value2”: 5},
4: {“value1”:“y”, “value2”: 5},
5: {“value1”:“y”, “value2”: 5}
}

I don’t know what could be wrong with my code…
Thanks for helping

Hi, this is a common mistake when working with OOP. Var is an object. so when you add it to the dictionary, you are not assigning the value to your dictionary “variable”, instead you are assigning the objects reference to it. So when you change the value of i_x or i_y, you are changing the object saved in all dictionaries position where you assigned it. Do i explain myself? instead you coud do this:

func write_in_dictionnary(dict, list):
    var local_dict = dict
    var i_x = 0
    var i_y = 0
    for key in local_dict:
	if local_dict[key]["value1"] == "x":
		var value = i_x
		local_dict[key]["value2"] = list[0][value]
		i_x += 1
	else:
		var value = i_y
		local_dict[key]["value2"] = list[1][value]
		i_y += 1
return local_dict

Notice that i use a new variable, that is local to the loop, so each iteration, it’s a new reference. And then i save it to the dict, instead of saving directly i_x and i_y. I think it would be better if we could just access the value of the objects i_x and i_y, with something like i_x.value() but i could not find the way. The code i posted above however works for me.

Tell me if this solves your problem or if this does not help you!

p7f | 2018-12-02 14:55

Hi, thank you for the answer.
I’m quite surprise that the problem is about references; at least in the code I posted. Because each time, in the loop, I’m working with a precise index in the array and a precise key in the dictionnary, I’m not moving objects.
i_x and i_x are only the values I use to target the ‘sub-array’ indexes (which contain raw ints and not references that could be moved throughout the iterations)

I still tried your code but it doesn’t works for me unfortunatelly. Maybe the problem is located earlier in my whole code, I’m still investigating, (even if I’m not playing with references at all to fill that dictionnary).

But thanks to have spend some time to examine my issue

snk | 2018-12-02 17:13

Hi, you are right… i did not read your code thoroughly. However, the code i posted worked fine in my machin. Could you share complete code so we can find a solution? I’ll change my answer to comment so other people can se it’s not resolved yet.

p7f | 2018-12-02 22:18

Well it seems to me that the vars (var i_x var i_y) behave like objects, instead of ints. Which version of godot are you using, if you’re using godot 3.1, try and use useage hints.

Also i would advise you not to change a dic, while you’re iterrating over it. It can lead to really strange side effects.
Try to create a new dict for local_dict, while iterrating over the dict, you get as paramter.

coffeeDragon | 2018-12-03 11:20

I tried your first code fragment, line for line, and it works just fine. Weird.

SIsilicon | 2018-12-03 22:22

Are you sure your code doesn’t work? It works just fine for me.

SIsilicon | 2018-12-04 13:37

yes, it works fine for me also

p7f | 2018-12-04 18:16

:bust_in_silhouette: Reply From: snk

Hi,
Thanks for the answers.

Couldn’t actually look at this last week, I had to work on other projects. So I reviewed all my code and I find from where the problem came. I was getting that dictionary from a .json file which contains 3 nested dictionaries. I wasn’t fully desassembling them when I parsed them, and I was copying the last one instead of copying all its values into a new one. The engine then was only creating a reference of it instead of creating a new one.

So when you are working with dictionaries, be aware that copying the whole dict instead of disassembling it to a new variable will only create a reference to it.