Why is value changing while iterating over a different part of a nested dictionary?

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

I’m iterating over a dictionary, and a value in a different part of the dictionary changes at a specific repeatable point if ‘i’ reaches 5. Between the two print statements below the value of eventMetadata[“stage2”][“texts”] changes, though I can’t see why. I broke down the steps of the assignment of conditions, which is why it’s over multiple lines, and the value in stage2 changes to an empty array, then changes to a different value when I assign condition. The value is a different value from the same JSON-style data file.

for j in eventStructure["stage" + str(i - 1)]["outcomes"].size(): 
			
	for k in eventStructure["stage" + str(i - 1)]["outcomes"][eventStructure["stage" + str(i - 1)]["outcomes"].keys()[j]].size():
				
		var condition = eventStructure["stage" + str(i - 1)]["outcomes"].keys()[j]
				
		if i == 5 and j == 2 and k == 1:
			pass # This is where I set the breakpoint having found the exact point

		self.eventMetadata[stage]["texts"].append(route.to.some.value)
		print(self.eventMetadata["stage2"]["texts"]) # value prints correctly
	
		self.eventMetadata[stage]["texts"].back()["conditions"] = []
		self.eventMetadata[stage]["texts"].back()["conditions"].resize(1)
		self.eventMetadata[str(stage)]["texts"].back()["conditions"][0] = {}
		self.eventMetadata[stage]["texts"].back()["conditions"][0]["condition"] = condition
		    
		print(self.eventMetadata["stage2"]["texts"]) # value has changed

is self.eventMetadata[stage] that you’re appending to, part of the very dict that you’re iterating over?

Wakatta | 2021-01-09 01:05

Not at this stage in the program - eventStructure and eventMetadata are two separate dictionaries. Data from eventMetadata is added to eventStructure later.

However ‘stage’ is defined as (“stage” + str(i)), so while most of the iteration steps cycle through eventStructure, the i does index the nested dictionaries in eventMetadata.

I did a little more testing which showed that if I define ‘condition’ as a constant string (rather than a variable pointing to a string) none of the unexpected behaviour occurs.

I also found that if I use the same constants with the same value that they would have had during the part of the iteration where the correct value for “stage2” is set, to print what is in eventStructure during the part of the iteration doing “stage5”, condition prints to the correct value.

eventStructure["stage2")]["outcomes"].keys()[0] 

The above is unchanged so the problem is in evebtMetadata.

Essentially what I have is a class which is defining a metastructure for a dialogue event which is being procedurally generated. This class sets the parameters within which the generation can occur, and seeks to output a template.

I wonder if I should move away from these slightly unwieldy dictionaries into having each stage defined as a class? The reason for the dictionary with nested array with nested dictionaries is that I’m using castleDB for the data, which makes editing stuff outside the engine so easy, but reading the nested data inside Godot is a bit of a nightmare.

jamesgiddings | 2021-01-09 07:01

So I think it is something to do with me not remembering that dictionaries and arrays are passed by reference.

I did completely re-implement the whole system using classes rather than just dictionaries for the event structure (and it was worth doing, as the code is much cleaner now) but to my horror I hit the same problem again.

Anyway, I’ve added in plenty of .duplicate()s on my arrays and things are working, though I haven’t gone through and worked out exactly which ones need to be duplicated and which ones are fine to be passed by reference.

At least I know where the problem was!

jamesgiddings | 2021-01-12 16:44

Wow thank you for the clarity however in my tests classes and dictionary’s operate the same way with dict’s being faster on creation. Sorry i couldn’t help before you found a solution

Wakatta | 2021-01-13 22:57