Storing and retrieving data with dictionaries

Dictionaries are lists of values, where each value has a unique identifier called a key.
Dictionaries in programming are much like dictionaries in real life. If you think about physical dictionaries, each word is a unique identifier for the word's meaning.
If you know a word, you can find its definition in the dictionary. In code, dictionaries allow you to associate keys and values.
In Godot, you can store any number of values in a dictionary as long as each value has a unique key.
The purpose of this guide is to summarize how to use Godot dictionaries. We'll cover the following topics:
  • When you should and shouldn't use dictionaries.
  • How to create new dictionaries.
  • How to add values to a dictionary.
  • How to see the value for a given key.
  • How to do things with each key and value, using loops.
  • How to tell the number of items in a dictionary without using loops.
Different programming languages use different names to describe dictionaries
Some examples are maps, records, and associative arrays. They all offer more or less the same features.

When to use dictionaries

We use dictionaries when we need to find a piece of data based on another.
For example, imagine we're building a game where the player has an inventory. It could be something as complex as in World of Warcraft or something as simple as in Forager.
Despite their differences, they both need a way to store the amount of each item the player owns.
We could use the item's name as a key and associate each key with a number: the amount of this item the player owns.
Somewhere in the depths of our game code, there would be a dictionary storing the key "potion" and the corresponding value of 3 to mean that the player owns three potions.
Godot dictionaries are very efficient. You can put values into them, read values already in them, and remove values from them quickly.
One of the best features of Godot dictionaries is that keys could be anything: strings, numbers, vectors, and even references to nodes.
For example, you could use a dictionary to keep track of all the entities on a map in a grid-based game. Your dictionary could look like this:
var game_board := {
	Vector2(2, 2): $Player,
	Vector2(5, 1): $Slime1,
	Vector2(7, 1): $Slime2,
}
You can read this dictionary like this:
  • On the grid cell with coordinates Vector2(2, 2), we have the Player node.
  • On the grid cell with coordinates Vector2(5, 1), we have the Slime1 node.
  • On the grid cell with coordinates Vector2(7, 1), we have the Slime2 node.
Dictionaries in Godot are very flexible. You will discover many uses for them in your games.

When to not use dictionaries

Dictionaries are not the best tool in every situation.
When all you need is a single list of values, you're better off storing them in an array. For example, if you need to store a list of enemies to spawn as part of a wave in a tower defense game, an array works great.
Also, every key in a dictionary must be unique. If you need to repeat the same value multiple times in a list, you should use an array.

Creating dictionaries

To create an empty dictionary, you write an empty pair of curly braces:
var inventory := {}
You can pre-populate the dictionary with some starter items if you like:
var inventory := {
	"potions": 1,
	"arrows": 10,
}
You write each key-value pair like this: key: value. The keys and values of a dictionary can be of any type: numbers, vectors, strings, nodes, etc.
onready var enemy_node = $Enemy
onready var player_node = $Player

var is_active := {
	enemy_node: false,
	player_node: false,
}
If that looks difficult, don't worry. It's good to know that it's possible. You can always try it when you get further along in your game development journey.

Storing new values in a dictionary

There are two ways to add values to a dictionary. They are, in no particular order:
  • Using square bracket syntax.
  • Using dot notation syntax.
In most situations, you can use them interchangeably.
Imagine that we have a variable named inventory that starts as an empty dictionary.
var inventory := {}
The most common way is to use the square bracket syntax:
inventory["arrows"] = 10
You can also use the dot notation.
inventory.arrows = 10
Notice that we don't use quotes around arrows, and we don't wrap the key and value in parentheses. This notation only works with string keys that have no space or special characters. It doesn't work with numbers or other types. For that reason, it's not recommended.
In both cases

Both notations also work with nodes!

You can also use both syntaxes when accessing the properties of nodes. Usually for nodes we use the dot notation because we know the properties we want to access and it gives us better error reporting:
@onready var timer: Timer = %Timer

func _ready() -> void:
	# Set the timer to last 2 seconds
	timer.wait_time = 2.0
We can use square brackets as well!
@onready var timer: Timer = %Timer

func _ready() -> void:
	timer["wait_time"] = 2.0
As with dictionaries, the square bracket notation allows you to compute property names while the game is running, from variables, for example. It's used way less often with nodes, but it's good to know it's there.
, the inventory dictionary will end up looking like this:
{"arrows": 10}
The square bracket notation also has the benefit that it allows you to compute keys while the game is running, from variables for example. We will see an example below (see: "Bonus: Dictionaries as Sets").

Reading temporary dictionary values

You can use almost the same syntax to read values as you set them. You can use three kinds of syntaxes to read the values:
  1. Using square bracket syntax.
  2. Using the get() function.
  3. Using dot notation syntax.
You know how to use the square bracket syntax:
var inventory := {
	"potions": 1,
	"arrows": 10,
}

var number_of_potions = inventory["potions"]
var number_of_arrows_with_default = inventory["arrows"]
The get() function works similarly to the set() function, with one small twist:
var inventory := {
	"potions": 1,
	"arrows": 10,
}

var number_of_potions = inventory.get("potions")
var number_of_arrows_with_default = inventory.get("arrows", 0)
var number_of_shields = inventory.get("shields", 0)
The get() function will return whatever is stored in the provided key string. If the key is not defined, in the dictionary, get() will return null. If you provide a second argument to get(), that value will be returned instead of null.
This is helpful because it means you can be sure you're getting back a value of the right type. If your game expects some amount of items, then getting null instead of a number could cause bugs. Using the get() function helps to prevent bugs.
You can also use dot notation and square brackets to read the values stored in a dictionary:
var number_of_potions = inventory.potions
Similarly to setting values, dot notation only works for strings, and, because Godot cannot verify if a property exists, it doesn't get autocomplete. To document the difference between dictionary keys and general properties, we avoid dot notation.

Verifying keys exist

It can be tempted to check if a key exist by using object[key] directly, like this:
var inventory := {
	"potions": 0,
	"arrows": 0,
}

if inventory["arrows"]:
  # do something
But in case "arrows" is equal to 0, or null, or false, then the code in the if branch won't be executed.
Instead, you can use the has() function to check if a key exists in a dictionary:
var inventory := {
	"potions": 0,
	"arrows": 0,
}

if inventory.has("arrows"):
  # do something
The has() function returns true if the key exists, and false if it doesn't.
There is also the has_all() function, which takes an array of keys:
var inventory := {
	"potions": 0,
	"arrows": 0,
}

var has_all_items = inventory.has_all(["potions", "arrows"])
You can also use the equivalent in operator:
var inventory := {
  "potions": 0,
  "arrows": 0,
}

if "arrows" in inventory:
  # do something

Looping over the keys and values of a dictionary

It's common to want to do something for each key or value in a dictionary. We use loops for this.
You're probably already familiar with the concept, but let's recap how for loops work with dictionaries.
  1. A for loop creates a temporary variable: a cursor that points to every value in an array. With a dictionary, by default, the for keyword loops over every key.
  2. The body of the for loop, which is the indented code below the for x in y line, is run for each dictionary key.
  3. The limit is tested to see if there are more possible values for the cursor.
    • If so, the loop body is run with the next possible cursor value.
    • Else, the loop ends.
There are two different lists of data we can iterate over when dealing with dictionaries:
  1. We can loop over all the keys in the dictionary.
  2. We can loop over all the values in the dictionary.
In Godot, using the for x in dictionary: syntax loops over the keys by default.
var inventory := {
	"sword": 1,
	"potions": 3,
}

func _init() -> void:
	for key in inventory:
		# This prints the amount of each item.
		print(inventory[key])
Notice how we have to put the for loop in a function to run it as instructions like these cannot run outside functions. We use the _init() function in this example. It's a function called when the script is first instantiated and that is available to all scripts in Godot, even if they don't extend a node type built into Godot.
In the example above, key will be equal to "sword" during the first loop iteration and "potions" during the second iteration.
The syntax for key in inventory: implicitly calls the function inventory.keys(), which returns an array containing all the keys in the dictionary.
To iterate over the values, we need to call the inventory.values() function explicitly to get all values as an array.
We can choose to loop over the values if we don't care about the keys:
for value in inventory.values():
	# Like before, this prints the amount of each item.
	print(value)
There's an equivalent function to obtain all the keys:
for key in inventory.keys():
	# This prints the name of each item.
	print(key)
writing for key in inventory is equivalent to writing for key in inventory.keys().

Determining the size of a dictionary outside of a loop

Dictionaries have a size() function that returns the number of key-value pairs present in the dictionary. This number will be 0 in an empty dictionary.
There's also an is_empty() function that returns true if no key-value pairs are present and false if at least one key-value pair is present.
The difference between using is_empty() and size() will depend on what your game needs to do at the moment. Here's an example of one way you might use the is_empty() and size() functions:
var inventory := {
	# keys and values
}

func show_inventory() -> void:
	if inventory.is_empty():
		show_empty_message()
	else:
		if inventory.size() < 5:
			display_inventory_as_grid()
		else:
			display_inventory_as_list()

Bonus: Dictionaries as Sets

There are cases where the use of a dictionary allows us to avoid unnecessary processing of a list of data. You can use a dictionary as an array that only contains unique values. Consider the following example:
var list_of_fruits := ["apple", "banana", "apple", "orange"]
This is a list in which I can have "apple" twice. Compare with the below:
var list_of_fruits := {
  "apple": true,
  "banana": true,
  "orange": true,
}
In this dictionary, you can't duplicate a key. If we had "apple" twice.
This would give us an error:
var list_of_fruits := {
  "apple": true,
  "apple": true,
}
This wouldn't give us an error, but the last time we set "apple" would overwrite the first time:
var list_of_fruits := {
  "apple": true,
}
list_of_fruits["apple"] = true
In other words, there will only ever be one single "apple" key in the dictionary; as well as one single "banana" and one single "orange".
We chose true here for the value, but it is unimportant; while it's traditional to use true, but you could use null, 0, or any other value. We're only interested in the keys.
Apart from uniqueness, the other benefit is that if you want to check the existence of "apple" or "orange", you can do it in constant time. This is not the case with arrays, where you have to loop through the entire list to check if an item is present; in the worst case scenario, like for "orange" which is the last item, you have to check every item in the list. For most games, this is not a performance problem, but for very large lists, it can be.
In some programming languages, an array with unique values is called "a set". In Godot, there are no sets, so we make do with dictionaries.
Here's a more complicated example: let's say you're making an alarm clock application, where the user can choose days of the week to run the alarm for. Clearly, this is a list of days. But you also don't want it to contain "Monday" twice.
A good pattern for this is a dictionary that has days as keys. For example:

var selected_days := {}

func add_day(day: String) -> void:
	# if `day` is not present in the dictionary, it will be added
	# if `day` is already in the dictionary, nothing will change
	selected_days[day] = true

func remove_day(day: String) -> void:
	# if `day` is in the dictionary, it will be removed
	# if `day` is not in the dictionary, nothing will happen
	selected_days.erase(day)

func get_selected_days() -> Array:
	# extracts all the keys and returns them as an array
	return selected_days.keys()

Summary

Dictionaries are a powerful data structure. They are useful whenever you need to associate two pieces of data, like an item's name and the amount of it in an inventory, or a pawn and its position on a game board. We've also seen how we can use them for dialogues and scores.
Every game developer needs to learn about dictionaries to make any non-trivial game. I encourage you to take all the time you need to master this subject.
If you want a shorter refresher on dictionaries for later, there's always the dictionary glossary page.

Lesson Q&A

Use this space for questions related to what you're learning. For any other type of support (website, learning platform, payments, etc...) please get in touch using the contact form.

  • Error: Function "set()" not found in base Dictionarynedlooked through the docs and could not figure it out. using Godot 4.2.2 stable 2 1 Jun. 07, 2024
  • What to do?pikminfan71Hi how are you guys doing? I wanted to ask if you have any good Ideas or suggestions for what to do if I finished m7 and waiting for the next module? do everything again? try to make something? thanks in advance! 2 1 Jun. 03, 2024
  • Minor TypoMrBright01In the "looping over keys and values in a dictionary", near the end between the two small examples, it says "There's an equivalent function to obtain all they keys:" 1 0 Oct. 31, 2024
  • Duplicated keys in list_of_fruits dictionaryEasySpeedsWhen you say to compare the two list_of_fruits under the Bonus section, both the array and dictionary have 2 "apple" entries. I think you intended to highlight the second "apple" in red or just remove it from the dictionary. 1 0 Sep. 12, 2024
  • I don't understand a part of "Verifying keys exist"StonemonkeyThere is a sentence: The `has()` function returns `true` if the key exists, and `false` if it doesn't, even if the value is `null`, `false`, or `0`. I don't understand the scenario "...even if the value is null, false, or 0" If the key doesn't exist what associated value is being referred to? Maybe I'm not reading this correctly. Do you mean if there is a key but it's value is null, false or 0 it will still return true? 1 0 Jul. 07, 2024
  • Just wanna say fantastic module, more of this please~ChunkyBitesJust very happy with these lessons overall, exactly what i was hoping to get out of the course! Getting an in-depth look at Control nodes is super appreciated, as someone whose focus is on UI & text heavy games. Explanations on arrays + dicts are also extremely helpful! Storing dicts inside arrays and then inside another array never even occurred to me as an option, lol. 1 0 Jun. 11, 2024
  • Small typopolitical-magpieIn the "Determining the size of a dictionary outside of a loop" section, all the instances of empty() should be replaced with is_empty() 1 0 Jun. 01, 2024
  • Getting error from code block exampleecstatic-herring```javascript var inventory := { "potions": 1, "arrows": 10, } var number_of_potions = inventory["potions"] var number_of_arrows_with_default = inventory["arrows", 0] ``` When I put this code in the Godot editor I get an error at line number 7. Not sure if it's a typo. 1 0 May. 30, 2024
  • Confused by "Dictionaries as Sets" sectionnear-octopusI don't really understand what is meant by the "Dictionaries as Sets" section? The final function returns an array, which makes the most sense for days of the week to be stored to me. Why store as a dictionary if they just get returned as an array anyway? It also seems to contradict the "When to not use dictionaries" section since this is a single piece of data. 3 0 May. 26, 2024
  • Slight mix-up in the first looping example?SingleMom420Under the first code block introducing iterating through dictionaries, it says "In the example above, `key` will be equal to `"sword"` during the first loop iteration and `"potions"` during the second iteration," however the code in that block returns the values, not the keys. 2 0 May. 18, 2024
Site is in BETA!found a bug?