Exploring Ruby Hashes: A Deep Dive into Data Manipulation

What is a Ruby hash?

A hash is an efficient data structure that lets you store data in UNIQUE key-value pairs. It’s like a kind of dictionary that you can build & use to quickly search for something.

The “word” in this dictionary is the key, and the “definitions” are the values stored under each key.

How is this different from arrays?

Well, arrays store data in a sequential, numerical index, so the only way to retrieve a specific item is to know this index number, which by itself doesn’t have much meaning.

But hash keys can be normal words like “stock_available”, which have meaning & therefore are easier to work with.

So you’ll use arrays for LISTS of things (like a list of fruits) & hashes for a DICTIONARY of values.

Example uses include:

  • A list of country names & their corresponding country codes (like ES ⇾ Spain).
  • A language dictionary, where every word has a list of possible definitions.
  • A list of domain name & their corresponding IP address.

One big advantage of hashes is their data retrieval speed, which is very fast if you know the key.

Make sure to take advantage of this if your data fits within a dictionary-like format.

How to Create a Hash

Ok.

I think you got a general idea of what is a hash, but how do you create one?

Like this:

{}

That’s an empty hash!

A hash with three key/value pairs looks like this:

{ a: 1, b: 2, c: 3 }

Where a is a key, and 1 is the corresponding value for that key. Notice that the key-value pairs are separated by commas.

Now:

Let’s look at how you can use hashes in your Ruby projects with common hash methods.

Storing Hash Values

You can create a hash with a set of initial values, as we have already seen.

Here’s another example:

fruits = { coconut: 1, apple: 2, banana: 3 }

Another option is to add new values to an existing hash.

Like this:

fruits[:orange] = 4

We are asking the Ruby programming language to store the value 4 (an Integer) inside a “drawer” named :orange (a Symbol).

NOTE: Why is there a colon before the word :orange when we access a value, but when we create the hash it looks like orange:? It’s just a syntax thing, don’t worry too much about it, but on old code you may find the hash-rocket (=>) symbol, which is still valid but outdated.

Values inside a hash can be any kind of Ruby object.

Including:

  • Strings
  • Integers & Floats
  • Arrays

Keys can also be anything, but symbols (like :banana) & strings are the most common type of keys you’ll find.

Remember that…

Keys are unique, we can only have one :orange key, or one :apple key.

When you add the same key twice you change its value.

How to Access Values From a Hash

You access a hash by key.

If you need to access the values directly, then a hash may not be the right structure for your data.

Example:

fruits[:orange]
# 4

This is the whole point of hashes, to quickly look up an item by its key.

If a key doesn’t exist, you’ll get nil.

fruits[:peach]
# nil

As an alternative, you can use the fetch method, which allows you to provide a default value.

Example:

fruits.fetch(:peach, 0)

If you use fetch without a default value (the 2nd argument), Ruby will raise a KeyError exception.

That’s helpful because you’ll know what key is missing.

How to Merge Two Ruby Hashes

You can take two hashes & merge them into a new hash.

What method does this?

Well, it’s not hard to guess this one. The method’s name is merge.

Here’s how to use it:

defaults    = { a: 1, b: 2, c: 3 }
preferences = { c: 4 }

defaults.merge!(preferences)
# {:a=>1, :b=>2, :c=>4}

Notice that because keys are unique, newer values overwrite older values.

You could use this fact for interesting solutions, like creating a “defaults” hash that users can override by passing their own hash.

If you need more control over how keys are merged you can pass a block.

Like this:

defaults.merge!(preferences) { |key, old, new| [old, new].max }

Where old are the values coming from defaults, and new are the values coming from preferences.

Multiple Values For One Key

In a dictionary…

Words are unique, but they can have multiple values (definitions) associated with them.

You can do this in Ruby!

Example:

dictionary = {
  opportunity: [
    "a set of circumstances that makes it possible to do something",
    "a situation or condition favorable for attainment of a goal"
  ],
  creativity: [
    "the use of imagination or original ideas to create something new",
    "the ability to create",
    "the process where new ideas emerge from combining existing ideas in new ways"
  ]
}

dictionary[:creativity][1]

Where dictionary[:creativity] gives you an array & [1] gives you the 2nd element from that array.

In other words:

The key is a symbol & the values are arrays. When you access the hash you get an array back which you access normally, like any other array.

How to Sort a Hash

You can sort arrays. But did you know that you can also sort hashes?

When you sort a hash, it’s sorted by key.

Example:

{ b: 1, a: 2 }.sort

# [[:a, 2], [:b, 1]]

But you can also sort them by value:

{ c: 3, b: 1, a: 2 }.sort_by(&:last)

You’ll notice that what you get from sorting a hash is not another hash…

It’s an array!

But you can convert this array back into a hash, using the to_h method.

Get All Keys & Values From a Hash

If you want a list of all the hash keys, good news, there is a method for that!

Here it is:

{ apple: 1, banana: 2 }.keys

# [:apple, :banana]

There’s also a method that gives you an array containing the values:

{ apple: 1, banana: 2 }.values

# [1, 2]

If you want to know if a key exists in a hash, instead of getting an array of them, use the key? method (btw this is an alias for include? & has_key? on the Hash class).

Example:

h = { ice_cream: 1, chocolate: 2, beer: 3 }

h.key?(:ice_cream)
# true

h.key?(:tomato)
# false

As you can see, this method returns a true or false value, also known a a Boolean value.

Summary

You’ve learned about Ruby hashes, a helpful data structure that is composed of key-value pairs. You also learned how to access a hash by key, and how to store new data in a hash.

Now open up irb (or pry) & start playing with hashes!

Thanks for reading 🙂