A question about modifying Arrays and Dictionaries.

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By JTJonny
:warning: Old Version Published before Godot 3 was released.

why does this work in some places: graph_dict[keys[i]].erase(vert) , but other places it does nothing (doesn’t even crash) .

I have to replace it with something like this:

		var neighbors_to_modify = graph_dict[keys[i]]
		neighbors_to_modify.erase(vert)
		graph_dict[keys[i]] = neighbors_to_modify

In the second code sample, the last line is not needed because dictionaries and arrays are reference types.
Other than that, I don’t know how to answer the problem. What’s your definition of “not working”? Did you create dictionaries and arrays by writing Array() or Dictionary() by any chance? (instead of [] or {})

Zylann | 2017-09-27 00:20

I use and {}. I was just wondering why I couldn’t use graph_dict[keys[i]].erase(vert). It seemed to not change the reference at all. I Also tried it without the last part and it doesn’t work, maybe it has something to do with it being so nested.

JTJonny | 2017-09-27 04:06

To find your problem, your example should contain data. We have no idea what is in graph_dict, keys or which value/type “vert” has.

Example (untested):

var keys = ["a","b","c"]
var graph_dict= { "a": {"keyA":"abc", "keyB":123},
   "b": {"keyA":"y", "keyB":42},
   "v": {"keyA":"x", "keyB":123}}
graph_dict[keys[0]].erase("keyB")

wombatstampede | 2017-09-27 08:56

The graph_dict is a Dictionary of Vector2s that calls an Array of Vector2s
{Vector2:[Vector2, Vector2]}

Here is the complete function:

func remove_verts_from_dict_graph(graph_dict, remove_vert_array):
	for vert in remove_vert_array:
		graph_dict.erase(vert)

	var keys = graph_dict.keys()
		
	for vert in remove_vert_array:
		for i in range(graph_dict.size()):
            # this does not work  graph_dict[keys[i]].erase(vert)
			var neighbors_to_modify = graph_dict[keys[i]]
			neighbors_to_modify.erase(vert)
			graph_dict[keys[i]] = neighbors_to_modify

	return graph_dict

JTJonny | 2017-09-27 20:03

Ok, if I get it right then you use a Vector2 as Key for erase?

Actually, I never used anything other than strings as keys in dictionaries so my experience here is a bit limited.

But if that is true, then you basically use a vectoy consisting of 2 float values for comparison (in erase). And as you might know, comparing floats with == is risky. Normally, you compare floats like this: abs(float2-float1) < margin_of_error. Where margin_of_error is a low value depending on your typical number range (i.e. 0.0001). With Vector2, it may be something like (Vector2-Vector1).length() < margin_of_error.

#1:
You can check, if this “comparison” problem is actually the problem here. Simply output the result of dictionary.has(key) before using erase and you’ll know if there’s actually a match to erase.

#2:
You could use a key which is comparable. I.e. use a string-representation with rounded values. Naturally, this uses additional CPU.

wombatstampede | 2017-09-28 06:30

Note that it should be fine if the vectors contain integer positions, and is actually a good solution to implement a spatial hash in GDScript. But of course you need to be aware of the fact numbers are still floats, and they will start to be off above some limit.

Zylann | 2017-09-28 18:34

Thanks for the info everyone. I don’t think its a comparison problem. These vectors don’t change, they only get deleted and reloaded as the exact same value. Once their made I never reference anything again. The longer code works just fine, I was just wonder about why the shorter version doesn’t. I think I’ll hide this question soon.

JTJonny | 2017-09-28 21:52

:bust_in_silhouette: Reply From: Vintagegodotuser

Its a long gone question, but I might have an answer for it:

It is defenitely no comparison problem.

The first part of the routine should erase every record which is keyed with any of the “vert” arguments handed over inside of the array.

The second part should remove every occurance of any “vert” argument from the payloads of the remaining records (graph_dict[keys[i]] = array).

Godot seems to work a bit strange handling arrays or dictionarys while iterating over their contents. Obviously those vars are locked (like a const!), so any changes are simply ignored without error message. That’s why the changes have to be bypassed via multiple copies. The iteration in the first part is no problem, because the iterated range is not changed.

I had the same problem and it took me almost three hours until I got the idea.