Hashes and symbols in Ruby


In this article, we'll keep exploring hashes and we'll discover what symbols are. For a refresher on hashes, I wrotethis.

Introduction to nil

In Ruby, nil is a way to say that a value doesn't exist. So, if we have a Hash and we try to access a value that doesn't exist:

my_hash = {
    "name" => "Damien",
    "age" => 26,
    "nationality": "French"

puts my_hash["lastName"] # puts nothing, because nil. lastName key doesn't exist

No error thrown, Ruby just tells you that nothing exists there by telling you... nothing :D

However, you can specify a default value in a Hash. That default value will be returned instead of nil when Ruby doesn't find a value inside a Hash:

with_default = Hash.new("No value found here!!!")

puts with_default["name"]  # puts "No value found here!!!"
puts with_default[42] # puts "No value found here!!!"


Let's start with the syntax. Symbols always start with a colon : and they must be a valid variable name:

my_symbol = :this_is_a_symbol

Symbols can be used as hash keys or to reference a method's name.

Hash's key

Symbols are a good use for hash keys because they are immutable. You can't change a symbol once its defined. Only one copy of a symbol can exist at one time, so they do not consume a lot of memory. These two reasons makes symbols as keys faster than strings as keys.

my_hash = {
    :one => "One",
    :a_symbol => 42,
    :boom => true

puts my_hash
# {:one=>"One", :a_symbol=>42, :boom=>true}

Converting between symbols and strings.

Ruby provides methods to convert a symbol to a string and vice versa. The method .to_s converts a symbol to a string while .to_sym does the opposite. The method .intern does the same thing than .to_sym

puts :this_is_my_shiny_symbol.to_s # this_is_my_shiny_symbol
puts "look_at_this_string".to_sym # :look_at_this_string
puts "HelloWorld".intern # :HelloWorld

Hash rocket syntax

You saw that we used a => between the key and the value in a hash. This is called the hash rocket syntax. However, you can also use a shorter syntax. To do so, remove the => and place the colon at the end of the symbol. The syntax resembles a javascript object now:

symbols_as_keys = {
    one: "two",
    three: "four"

The keys are still symbols. However, this syntax doesn't work with strings as keys.

Be more selective

We can grab a value from a hash when we have its associated key. But how would we filter a hash to only retrieve values that meet some criteria? We could use .select

restaurant_ratings =  {
    soleia: 6,
    auberge_du_printemps: 3,
    pauls: 4,
    olive_garden: 7

Let's use select to filter restaurants with a rating strictly superior to 5.

puts restaurant_ratings.select{ |restaurant, rating|
 rating > 5

# {:soleia=>6, :olive_garden=>7}

Now, let's get the restaurants where the rating is equal to 3

puts restaurant_ratings.select{ |restaurant, rating| 
  rating == 3

# {:auberge_du_printemps=>3}`

Just the keys? Or just the values

Because Ruby is awesome, you do not need to iterate over keys AND values if you don't need one of them. With .each_key , you'll iterate only over the keys and with .each_value , you will get only the values:

restaurant_ratings.each_key{|k| puts k}

# soleia
# auberge_du_printemps
# pauls
# olive_garden

restaurant_ratings.each_value{|v| puts v}

# 6
# 3
# 4
# 7