Skip to content

Dict

Built-in type · Written [“Ada”: 36, “Grace”: 45], or [] for an empty one

A Dict, short for dictionary, pairs each key with a value, so a value can be looked up by its key: a person’s age by their name, a word’s meaning by the word. Its type is written with both, as Dict[String, Int]. On this page, K stands for the key type and V for the value type.

var ages = ["Ada": 36, "Grace": 45]
ages["Linus"] = 28 # adds an entry
ages["Ada"] = 37 # changes one
print(ages["Grace"]) # prints 45
for (name, age) in ages {
print("#{name} is #{age}")
}

An empty dictionary needs its type written out: var ages: Dict[String, Int] = []. It prints as [:].

Looking up can miss, so ages["Nobody"] gives nothing rather than raising an error, and its type is Int?. Give a fallback with .or, as in ages["Nobody"].or(0), or check contains_key? first.

A dictionary keeps its entries in the order they were added, for for loops and printing. Changing an entry’s value keeps its place. Two dictionaries are equal when they hold the same entries, in any order.

A key must be a value that never changes: a number, Bool, String, an enum value, or a tuple or struct made only of those. A list, another dictionary, or an object cannot be a key, since it could change after it was stored and never be found again.

Like a list, a dictionary is a value: assigning it to another variable gives that variable its own copy. Only a var dictionary can change.

Blocks given to a dictionary’s methods receive each entry as a pair, written { (name, age) => ... }.

Size and lookup
count, empty?() How many entries it has
contains_key?(key), contains_value?(value) Whether a key or value is in it
keys(), values(), entries() Its keys, values, or entries as a list
Changing it
remove(key) Remove an entry
merge(other) Add another dictionary’s entries
Making new dictionaries
map_keys { ... }, map_values { ... } Each key or value changed by a block
filter { ... }, reject { ... } The entries a block accepts, or rejects
Visiting and asking
each { ... }, each_with_index { ... }, reverse_each { ... } Run a block for each entry
map { ... }, flat_map { ... }, filter_map { ... } A list made from the entries
find { ... }, find_index { ... } The first entry a block accepts
any? { ... }, all? { ... }, none? { ... }, one? { ... }, count_where { ... } Questions about the entries
Operator Meaning Example
dict[key] The value for a key, or nothing ages["Ada"] → 37
dict[key] = value Add an entry, or change one ages["Linus"] = 28
== != Compare ["b": 1, "a": 2] == ["a": 2, "b": 1] → true

To add to a value that may not be there yet, give it a fallback: scores["Ada"] = scores["Ada"].or(0) + 1.

count: Int

How many entries the dictionary has.

["Ada": 36, "Grace": 45].count # → 2

empty?(): Bool

Whether the dictionary has no entries.

["Ada": 36].empty?() # → false

contains_key?(key: K): Bool

Whether the dictionary has an entry for key. This also tells a missing entry apart from one whose value is nothing.

["Ada": 36].contains_key?("Ada") # → true

contains_value?(value: V): Bool

Whether any entry has the value value.

["Ada": 36, "Grace": 45].contains_value?(45) # → true

keys(): List[K]

The keys, in order.

["Ada": 36, "Grace": 45].keys() # → ["Ada", "Grace"]

values(): List[V]

The values, in order.

["Ada": 36, "Grace": 45].values() # → [36, 45]

entries(): List[(K, V)]

Each entry as a (key, value) pair, in order.

["Ada": 36, "Grace": 45].entries() # → [("Ada", 36), ("Grace", 45)]

These change the dictionary, so they need a var dictionary. Adding and changing entries is done with dict[key] = value.

remove(key: K): V?

Removes the entry for key and gives back its value, or nothing when there was no such entry.

var ages = ["Ada": 36, "Linus": 28]
print(ages.remove("Linus")) # prints 28
print(ages) # prints ["Ada": 36]

merge(other: Dict[K, V])

Adds every entry of other. When a key is in both, it keeps its place and takes other’s value.

var ages = ["Ada": 36, "Grace": 45]
ages.merge(["Grace": 46, "Alan": 41])
print(ages) # prints ["Ada": 36, "Grace": 46, "Alan": 41]

These leave the dictionary as it was and give back a new one.

map_keys { key: K => K2 }: Dict[K2, V]

Each key changed by the block, with its value unchanged.

["a": 1, "b": 2].map_keys { key => key.upper() } # → ["A": 1, "B": 2]

map_values { value: V => V2 }: Dict[K, V2]

Each value changed by the block, with its key unchanged.

["a": 1, "b": 2].map_values { value => value * 10 } # → ["a": 10, "b": 20]

filter { (key: K, value: V) => Bool }: Dict[K, V]

The entries the block accepts, in order.

["Ada": 36, "Grace": 45].filter { (name, age) => age > 40 } # → ["Grace": 45]

reject { (key: K, value: V) => Bool }: Dict[K, V]

The entries the block does not accept.

["Ada": 36, "Grace": 45].reject { (name, age) => age > 40 } # → ["Ada": 36]

These work as they do for a List, with each entry given to the block as a (key, value) pair. The ones that make something new give back a list.

each { (key: K, value: V) => ... }

Runs the block for each entry, in order. It is the same as a for loop.

["Ada": 36, "Grace": 45].each { (name, age) => print(name) }
# prints Ada, then Grace

each_with_index { (key: K, value: V), index: Int => ... }

Runs the block for each entry, with its position.

reverse_each { (key: K, value: V) => ... }

Runs the block for each entry, from last to first.

map { (key: K, value: V) => U }: List[U]

A list of what the block gives for each entry.

["Ada": 36].map { (name, age) => "#{name}: #{age}" } # → ["Ada: 36"]

flat_map { (key: K, value: V) => List[U] }: List[U]

The items of every list the block gives, joined into one list.

filter_map { (key: K, value: V) => U? }: List[U]

What the block gives for each entry, leaving out every nothing.

find { (key: K, value: V) => Bool }: (K, V)?

The first entry the block accepts, or nothing.

["Ada": 36, "Grace": 45].find { (name, age) => age > 40 } # → ("Grace", 45)

find_index { (key: K, value: V) => Bool }: Int?

The position of the first entry the block accepts, or nothing.

any? { (key: K, value: V) => Bool }: Bool

Whether the block accepts at least one entry.

["Ada": 36, "Grace": 45].any? { (name, age) => age > 40 } # → true

all? { (key: K, value: V) => Bool }: Bool

Whether the block accepts every entry.

none? { (key: K, value: V) => Bool }: Bool

Whether the block accepts no entry.

one? { (key: K, value: V) => Bool }: Bool

Whether the block accepts exactly one entry.

count_where { (key: K, value: V) => Bool }: Int

How many entries the block accepts.

["Ada": 36, "Grace": 45].count_where { (name, age) => age > 30 } # → 2