DEV Community

loading...

Figuring Out Hashes In Ruby

Justin Bermudez
・5 min read

Hashes kind of look like this #. And are usually called hash browns which you can eat. Hashes in Ruby usually look like this
Hash = {key => value}

Hashes are one of the more important things to know how to do in any language. Once you understand how to manipulate a Hash, then Hash of Array, and then Hash of Array of Hash of Arrays. Then you are basically unstoppable.

You may know them in other languages where they are called dictionaries in Python and Swift, or Hashmap/Hashtable in Java. They all achieve the same thing where you can look up a value from the key it is associated with. But here we are going to take a closer look at Ruby and how they play with hashes.

How Do We Make Them?

We can make them in different ways depending on your style or your needs

Here is a general example of what a hash consists of

hash = {key => value}

They have a variable name to reference then followed by the actual hash. A key pointing to its value and surrounded by curly braces.
We can initialize them either with a constructor or just by creating the whole hash with key and value pairs.
Using a constructor

new_hash = Hash.new

And that is it! You created a hash with nothing in it. If you want to pass in key and value pairs, then you would call the newly created hash, with the key you want associated with it, then setting it equal to the value. This creates the key and the value you associated with.

new_hash['word'] = 5

new_hash['word']
=> 5

The other option to creating your hash is if you have some data you want to fill your hash with.
Without Constructor

new_hash = {
  :blue => 1, 
  :green => 2, 
  :red => 3
}

And there you go, you created a new hash with the data you filled it with!

Setting Up Your Keys

Your key value can be anything from an integer, string, or a variable, but like all languages has its syntax.
Using an integer or string as a key, you have to use the rocket ship arrow to set it up.

alpha = {'a' => 1}
alpha['a']
=> 1

number = {9 => 'z'}
number[9]
=> 'z'

But when we use a variable we have a little more freedom. We have to turn our variable into a symbol which basically adds ":" in either front or back of the variable. If we put the colon before the variable, then we have to use the rocket ship arrow like how we did above

var = 'a'
alpha = {:var => 1}

alpha[var]
=> 1

But if we put it after the variable, then we do not use the rocket ship arrow.

var = 'a'
alpha = {var: 1}

alpha[:var]
=> 1

Just make sure remember to pass in the variable as a key so put the colon before! We are also able to use variables that have no value as a key so we can do

alpha = {:var => 1}

alpha[:var]
=> 1

and things will be perfectly the same. You just cannot interchangeably use the variable and what the variable is assigned to in order to get the value.
A side note for when setting your keys in a hash, if you have the key pointing to nothing, then it is automatically nil.

alpha = Hash.new
# setting our key with no value
alpha[:var]

alpha[:var]
=> nil

It does not break our program and it does not give an error. Things are perfectly, it just means we have nothing there!

Well that's cool, what about our values.

Let us Look at the Values

Your key can basically point to anything, this is what makes hashes so powerful. You can store a key with a value of another hash if you will, or an array, or just another integer. Whatever your heart desires you just need to point to it.

There is not much explanation so I will just show you different values that are pointed at.

band_class = { 
        :bass => ['tubas', 'euphoniums', 'trombones'],
        :piccolo => 1
        :bass_clarinet => "can't hear that"
        :saxophones => {}
        :trumpets => 'F'
 }

Accessing Data in our Hash

Ruby is cool where we can do a lot of the same things in different ways. When we need to look at data in a Hash we iterate through it almost like an array. But instead of indexes, we reference the objects in a hash by the keys.

Let us try to checkout an example on how to get values from the key associated with it. We will use an example of a hash of dogs that have a number associated with it like so.

fav_dogs = {
      :pugs => 1,
      :shitzu => 2,
      :shiba => 3,
      :not_dogs => ['monkey', 'lizard', 'turtle']
}

Assume we just want the number associated with shitzu. We can either iterate through the hash or we can return it if we hard code it.
Hard coding to get the return value is easier if you know how to access the value like so
fav_dogs[:shitzu] # => 2
At the same time if you are asked to iterate through a hash instead then you would need to use either a for loop or use #each. This won't be very difficult if we use an enumerator to find what we want inside the hash.

fav_dogs.each do {|dog, number|
     if dog == :shitzu
         puts number
}
=> 2

See how in our enumerator we have |dog, number|. When iterating through hashes, we can have more than one enumerator to reference the key and value at the same time. Breaking down what we have, 'dog' is looking at the keys, so iterating through ={:pugs,:shitzu,:shiba,:not_dogs}

While on the other hand we have 'number'. This is looking at the value associated with the key that 'dog' is pointing to. So if our iterator stops at when dog == :shitzu, and we want its value. We can then call on 'number' which is already referencing the value of ':shitzu'. Basically dog and number move at the same time, so we never need to worry about either one being ahead or behind in the iterator.

Cool, so we now know how to get go through hashes with enumerators with the key and values. But what if we needed to look inside of a Hash of Array? This is one the more important skills to knowing how to go through a collection of collection basically. When you use API's for your projects or working on big data, you are going to need to know how to traverse through them.

Let us try to look at an example so let us bring back our doggies.

fav_dogs = {
      :pugs => 1,
      :shitzu => 2,
      :shiba => 3,
      :not_dogs => ['monkey', 'lizard', 'turtle']
}

You see what is inside of ':not_dogs'? An ARRAY, ohhhhhh. Do not worry, we basically have everything we need to know on how to get what is inside of that array(assuming you already know how to work an array). So if we want to output all the contents of ':not_dogs', we need to bring back our iterator from above.

fav_dogs.each do {|dog, number|
     if dog == :not_dogs
         puts number
}
=> ['monkey', 'lizard', 'turtle']

See what we changed there? Just the value of 'dog' that we want from ':shitzu' to ':not_dogs'. Since 'number' is already pointing at the value of ':not_dogs', then it will output the whole array. WOW, on the flip side we can hard code without iterating through the whole hash to get what we want since we know how to access the array.

fav_dogs[:not_dogs]
=> ['monkey', 'lizard', 'turtle']

This is but the BASICS of going through a hash and accessing its components to fill your needs. Somethings to remember is when you are hard coding to get a return value in a hash, do not forget to pass in a symbol. Those things with a ':'. Most of your errors will most likely come from not using the symbol. If you do not know what your enumerators are pointing at, do not forget to throw that into a console! Use gems like 'pry' or 'pp' to help break things down for you!

Discussion (1)

Collapse
dcrow profile image
Yaroslav Barkovskiy

Actually the following code does not work

var = 'a'
alpha = {:var => 1}

alpha[var]
=> 1

Same with

var = 'a'
alpha = {var: 1}

alpha[:var]
=> 1

They actually create a symbol key :var instead of a string key a

alpha.keys
=> [:var]

If you want to use the value from a variable(in this case var), then you should do it like this

var = 'a'
alpha = { var => 1 }

alpha[var]
=> 1

This code also does not work

fav_dogs.each {|dog, number|
     if dog == :not_dogs
         puts number
}

It seems you forgot an end somewhere(twice). Also as a side note {} blocks can be replaced with do...end blocks.

Something like this

fav_dogs.each do |dog, number|
     if dog == :not_dogs
         puts number
     end
end

fav_dogs.each { |dog, number|
     if dog == :not_dogs
         puts number
     end
}