Dictionaries: look up one thing by another

Hashes are another very useful, and widely used kind of thing that can be used to store other objects.

Unlike arrays which are mere lists, Hashes are like dictionaries:

You can use them to look up one thing by another thing. We say: we look up a value from a Hash using a key. Or one could say: Please get me the value that is associated with this key.

Imagine a real dictionary that translates from English to German. When you look up the English word “hello” then you’ll find the German “Hallo”. When you look up “one” then you’ll find “eins”, and so on. The authors of this dictionary have assigned a German word (a value) to an English word (the key).

Hashes work pretty much like this.

A Hash assigns values to keys, so that values can be looked up by their key.

We also refer to a value that is assigned to a key as key/value pairs. A Hash can have as many key/value pairs as you like.

Creating a Hash

In Ruby you can create a Hash by assigning a key to a value with =>, separate these key/value pairs with commas, and enclose the whole thing with curly braces.

This is how it looks:

{ "one" => "eins", "two" => "zwei", "three" => "drei" }

This defines a Hash that contains 3 key/value pairs, meaning that we can look up three values (the strings "eins", "zwei", and "drei") using three different keys (the strings "one", "two", and "three").

By the way, the Ruby community has come up with the name hash rocket for the bit of syntax => which separates a key from a value, … we think that is pretty cool to know :)

A Hash is created by listing key/value pairs, separated by hash rockets, and enclosed by curly braces.

Looking up a value

Now, how do you actually look up the value that is associated with the key "one"?

Just like with Arrays you use sqare brackets, but instead of passing a number indicating the position you now pass the key. Like so:

dictionary = { "one" => "eins", "two" => "zwei", "three" => "drei" }
puts dictionary["one"]

Do you reckognize how we, on the second line, use a variable name to refer to the Hash defined on the first line?

In this example, dictionary is a Hash defined on the first line. ["one"] looks up the value associated to the key "one", which is "eins". This value will be passed to puts which outputs it to the screen.

Setting a key to a value

Also, just like with Arrays, there’s a way to set key/value pairs on an existing Hash:

dictionary = { "one" => "eins", "two" => "zwei", "three" => "drei" }
dictionary["zero"] = "null"
puts dictionary["zero"]

This prints out null.

You could also overwrite existing key/values the same way. For example this would set the word "uno" to the key "one" (i.e. overwrite the existing pair with the value "eins"):

dictionary = { "one" => "eins", "two" => "zwei", "three" => "drei" }
dictionary["one"] = "uno"
puts dictionary["one"]

So, this would now output uno.

Any kind of objects

You can use any kind of object as keys, and you can store any kind of object as values.

For example, these are all valid Hashes, too:

{ 1 => "eins", 2 => "zwei", 3 => "drei" }
{ :one => "eins", :two => "zwei", :three => "drei" }
{ "weights" => ["pound", "kilogram"], "lengths" => ["meter", "mile"] }
{ :de => { :one => "eins", :two => "zwei", :three => "drei" } }

The first example uses numbers as keys, while the second one uses Symbols, which is quite a common thing to do in Ruby.

In the third example you can see that one can use Arrays as values in Hashes. So if you’d look up the key "weights" you’d now get an Array back.

Not quite sure where you’d use a Hash like the third line in real code, but the last line is actually pretty darn close to what Rails uses for translating strings to different languages:

It is also an example of a nested Hash. There’s another Hash associated (stored) as a value for the key :de (representing the language German). And this other Hash now has three key/value pairs. So a Rails programmer could look up how to translate “one” to German, and get “eins” back.

Hashes can use any kind of objects as keys and values.

On formatting: Note that there’s one space inside the curly braces on both sides, around the => Hash rocket, and after each comma. But there are, again, no spaces inside that square brackets [] that define the Arrays on the third line.

Missing values

What happens if we try to look up a key that does not exist?

Again, just as with Arrays, we’ll get back nil, meaning “nothing”:

$ irb
> dictionary = { "one" => "eins", "two" => "zwei", "three" => "drei" }
> dictionary["four"]
=> nil

Does this make sense?

Things you can do with Hashes

The main purpose of a Hash is being able to lookup a value by a key.

However, here are a few other things you can do with Hashes, too.

Again, look at them, and play with them in irb. Don’t necessarily put too much effort into memorizing all of them …

You can merge two Hashes:

$ irb
> { "one" => "eins" }.merge({ "two" => "zwei" })
=> { "one" => "eins", "two" => "zwei" }

fetch does just the same as the square bracket lookup [] discussed before, but it will raise an error if the key is not defined:

$ irb
> dictionary = { "one" => "eins" }
> dictionary.fetch("one")
=> "eins"
> dictionary.fetch("two")
KeyError: key not found: "two"

keys returns an Array with all the keys that a Hash knows:

$ irb
> dictionary = { "one" => "eins", "two" => "zwei" }
> dictionary.keys
=> ["one", "two"]

length and size both tell how many key/value pairs the Hash has:

$ irb
> dictionary = { "one" => "eins", "two" => "zwei" }
> dictionary.length
=> 2
> dictionary.size
=> 2

Exercises: Now would be a good time to do some of the exercises on Hashes.

Hash syntax confusion

You can skip the following and jump right to the chapter Variables, or you can keep reading if you’re curious.

We’ve found it’s important for us to explain the following somewhere in our book, because many online resources use another, alternative syntax for defining Hashes.

The term syntax, in programming, refers to ways to use punctuation in order to (amongst other things) create objects.

E.g. the fact that we can use square brackets [] and commas , in order to define Arrays, and curly braces {} and hash rockets => in order to define Hashes, is part of Ruby’s syntax.

Today, there are two different syntaxes for defining Hashes with curly braces, and they have the potential to confuse newcomers a lot.

There’s an old-style one, and a new, modern one.

We use the old syntax, and ignore the new one, for now.

Here’s why:

Up to a certain version of Ruby the syntax that uses hash rockets was the only syntax to create Hashes, and it works the same for all Hashes no matter what kinds of objects you use as keys.

Then, a few years back, a new syntax was introduced. Many Ruby programmers love to use it, because it takes a little less space, and it also looks a lot like JSON, which is a data format that is widely used in web applications.

The new Hash syntax looks like this:

{ one: "eins", two: "zwei", three: "drei" }

Using this syntax we tell Ruby that we want the keys to be symbols.

Hmmmm? We just learned that Symbols are defined by prepending a word with a colon like :one, right?

Well, yes, correct, but that’s just how it works: If you define a Hash using this syntax, then you’ll get a Hash that has Symbols as keys.

We found the new syntax pretty confusing for beginners: It is slightly less explicit and obvious, and you have to learn another piece of information. That’s why we simply ignore it in our study groups while we learn what Hashes are and how you can use them.

Once you feel comfortable using Hashes, you can make your own decision, and start using the modern syntax if you like it better.

In the meanwhile, whenever you see a Hash using the new syntax somewhere else, you now know what it means, and where to look it up. Simply remember that these two Hashes are exactly the same:

{ :one => "eins", :two => "zwei", :three => "drei" }
{ one: "eins", two: "zwei", three: "drei" }