Storing and retrieving data with dictionaries
- 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 dictionariesSome examples are maps, records, and associative arrays. They all offer more or less the same features.
When to use dictionaries
"potion"
and the corresponding value of 3
to mean that the player owns three potions.var game_board := {
Vector2(2, 2): $Player,
Vector2(5, 1): $Slime1,
Vector2(7, 1): $Slime2,
}
- 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.
When to not use dictionaries
Creating dictionaries
var inventory := {}
var inventory := {
"potions": 1,
"arrows": 10,
}
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,
}
Storing new values in a dictionary
- Using square bracket syntax.
- Using dot notation syntax.
inventory
that starts as an empty dictionary.var inventory := {}
inventory["arrows"] = 10
inventory.arrows = 10
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.Both notations also work with nodes!
@onready var timer: Timer = %Timer
func _ready() -> void:
# Set the timer to last 2 seconds
timer.wait_time = 2.0
@onready var timer: Timer = %Timer
func _ready() -> void:
timer["wait_time"] = 2.0
inventory
dictionary will end up looking like this:{"arrows": 10}
Reading temporary dictionary values
- Using square bracket syntax.
- Using the
get()
function. - Using dot notation syntax.
var inventory := {
"potions": 1,
"arrows": 10,
}
var number_of_potions = inventory["potions"]
var number_of_arrows_with_default = inventory["arrows"]
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)
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
.null
instead of a number could cause bugs. Using the get()
function helps to prevent bugs.var number_of_potions = inventory.potions
Verifying keys exist
object[key]
directly, like this:var inventory := {
"potions": 0,
"arrows": 0,
}
if inventory["arrows"]:
# do something
0
, or null
, or false
, then the code in the if branch won't be executed.has()
function to check if a key exists in a dictionary:var inventory := {
"potions": 0,
"arrows": 0,
}
if inventory.has("arrows"):
# do something
has()
function returns true
if the key exists, and false
if it doesn't.has_all()
function, which takes an array of keys:var inventory := {
"potions": 0,
"arrows": 0,
}
var has_all_items = inventory.has_all(["potions", "arrows"])
in
operator:var inventory := {
"potions": 0,
"arrows": 0,
}
if "arrows" in inventory:
# do something
Looping over the keys and values of a dictionary
for
loops work with dictionaries.-
A for
loop creates a temporary variable: a cursor that points to every value in an array. With a dictionary, by default, thefor
keyword loops over every key. -
The body of the for
loop, which is the indented code below thefor x in y
line, is run for each dictionary key. -
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.
- We can loop over all the keys in the dictionary.
- We can loop over all the values in the dictionary.
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])
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.key
will be equal to "sword"
during the first loop iteration and "potions"
during the second iteration.for key in inventory:
implicitly calls the function inventory.keys()
, which returns an array containing all the keys in the dictionary.inventory.values()
function explicitly to get all values as an array.for value in inventory.values():
# Like before, this prints the amount of each item.
print(value)
for key in inventory.keys():
# This prints the name of each item.
print(key)
for key in inventory
is equivalent to writing for key in inventory.keys()
.Determining the size of a dictionary outside of a loop
size()
function that returns the number of key-value pairs present in the dictionary. This number will be 0
in an empty dictionary.is_empty()
function that returns true
if no key-value pairs are present and false
if at least one key-value pair is present.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
var list_of_fruits := ["apple", "banana", "apple", "orange"]
"apple"
twice. Compare with the below:var list_of_fruits := {
"apple": true,
"banana": true,
"orange": true,
}
var list_of_fruits := {
"apple": true,
"apple": true,
}
"apple"
would overwrite the first time:var list_of_fruits := {
"apple": true,
}
list_of_fruits["apple"] = true
"apple"
key in the dictionary; as well as one single "banana"
and one single "orange"
.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.
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()
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.