About erasing multiple keys while iterating over a dictionary

Godot Version

4.3

Question

I would like to erase multiple keys in a dictionary while iterating, but I recalled from the document: Dictionary — Godot Engine (stable) documentation in English

Note: Do not erase entries while iterating over the dictionary. You can iterate over the keys array instead.

Note: Erasing elements while iterating over dictionaries is not supported and will result in unpredictable behavior.

But then, I would like to do it, so I tried it and see what will happen:

	var dd = {}
	for i in 5:
		dd[i] = i
		
	for i in dd:
		print(str(i) + " = " + str(dd[i]))
	
	for i in dd:
		dd.erase(i)
	
	for i in dd:
		print(str(i) + " = " + str(dd[i]))

The result:

0 = 0
1 = 1
2 = 2
3 = 3
4 = 4
1 = 1
2 = 2
3 = 3
4 = 4

So I see only key 0 is removed.

So I came up with this:

	var dd = {}
	for i in 5:
		dd[i] = i
		
	for i in dd:
		print(str(i) + " = " + str(dd[i]))
	
	var keyToRemove = []
	
	for i in dd:
		keyToRemove.append(i)
	
	for i in keyToRemove:
		dd.erase(keyToRemove[i])
	
	print("Dict Size: " + str(dd.size()))

The result:

0 = 0
1 = 1
2 = 2
3 = 3
4 = 4
Dict Size: 0

So it seems this might work. Is this the recommended way to erase multiple keys of a dictionary in Godot? I created a new Array for keeping which keys to erase, then iterate over this Array to erase the specified keys shortly afterward.

Question: Any concern that I should be aware of if I do it this way?

NOTE: the above code removed all keys but in my case, I only have several multiple keys to remove, not all.

Yes, I do it the same in my projects as well. Create a new Array and add all the keys or indexes to it that need to be removed, and then iterate through that Array to remove the elements from the original Array or Dictionary. Here’s one example from my project. Context shouldn’t matter, but you can see here that I do the same as you.

var time_events: Array[TimeEvent]

func _check_time_events() -> void:
	if not time_events.is_empty() and time_events[0].time <= now:
		time_events.sort_custom(_sort_time_events_ascending)
	
	var counter: int = -1
	var time_event_indexes_to_remove: Array[int]
	for time_event: TimeEvent in time_events:
		counter += 1
		if time_event.time > now:
			break
		time_event.notify_observer()
		time_event_indexes_to_remove.push_front(counter)
	
	for time_event_index_to_remove: int in time_event_indexes_to_remove:
		time_events.remove_at(time_event_index_to_remove)
1 Like

if you have array you can iterate from big index to small, after deleting object your array items will move only items with bigger index