Hashes
Hashes are the ideal container type for dealing with key/value pairs.
Creating a hash is simple. In the following example, we'll be creating a Hash with the type Hash(String, Int32)
friends_age = {
"John" => 42,
"Jane" => 31,
"George" => 50,
"Max" => 28,
}
p typeof(friends_age) # => Hash(String, Int32)
Accessing values
You can read a value using keys:
p friends_age["Jane"] # => 31
Trying to acces a value which doesn't exist will result in an exception:
p friends_age["Patrick"] # => Error: Unhandled exception, missing hash key "Patrick"
Therefore, we need to handle the outcome where a key might not exist with ?:
p friends_age["Jane"]? # => 31
p friends_age["Patrick"]? # => nil
Another way to handle this would be to use the predicate function has_key?
p friends_age.has_key? "Jane" # => true
p friends_age.has_key? "Patrick" # => false
Updating Values
We can update a value quite simply:
friends["John"] = 43
Creating Hashes
Just like arrays, declaring an empty hash with no values and no type information is not possible:
my_hash = {} # => Error: for empty hashes use {} of KeyType => ValueType
Instead we need to provide the type information:
my_hash = {} of String => Int32
my_hash_two = Hash(String, Int32).new
If you want to check if the hash is empty, you can use the empty? predicate:
p my_hash.empty? # => false
Examples of Different Syntax
There are different ways to declare key value pairs, have a look at the following declarations and their inferred types:
hash_a = {"a" => 1, "b" => 2, "c" => 3} # => Hash(String, Int32)
hash_b = {:a => 1, :b => 2, :c => 3} # => Hash(Symbol, Int32)
hash_b2 = {a: 1, b: 2, c: 3} # => NamedTuple(a: Int32, b: Int32, c: Int32)
hash_c = {"a": 1, "b": 2, "c": 3} # => NamedTuple(a: Int32, b: Int32, c: Int32)
If a hash uses symbols as keys, you can access them like so:
fruits = {:watermelon => 4.99, :banana => 2.00}
p fruits[:watermelon] # => 4.99
p "Keys: #{fruits.keys} Values: #{fruits.values}" # => "Key: [:watermelon, :banana] Value: [4.99, 2.0]"