Programming Fundamentals - Part 4 - Hashes

Arrays are useful for a list of similar types of things, or a random assortment of things.  But sometimes, we have very different things that need to be more explicitly identified.  For example, our favorite_foods array held multiple foods.  But what if we wanted to represent all our favorite things in code?  An array would be a little confusing:

favorite_things = ["Purple", 17, "Apple"]

Looking at that list, we don't know what the elements are.  Is "Apple" a favorite fruit, computer, or company?  Is "Purple" a favorite color or a favorite set of sheets?  With this type of data, it would be helpful to identify each element more clearly.  To do so, we use a Hash (known as a Dictionary in some languages).

A hash is a list of key-value pairs. Here is the same data from before, but using a hash:

favorite_things = { "color" => "purple", "number" => 17, "computer" => "Apple" }

Notice how we use curly braces { } to enclose the list of items, and we use commas to separate each item.  The "key" => value pair can be written this way with a string as the key and a fat arrow or hash rocket operator (=>) .  You may also see it represented as this:

favorite_things = { :color => "purple", :number => 17, :computer => "Apple" }

or this:

favorite_things = { color: "purple", number: 17, computer: "Apple" }

All versions are acceptable, but we'll use the first format.

To see another example of a hash, let's model a user's profile data as a hash:

let user = {
  "name" => "Ben",
  "location" => "Chicago, IL",
  "status" => "Staying warm!"
}

Similar to an array, the values within a hash can be anything, even other hashes or arrays.  Let's flesh out the location data:

let user = {
  "name" => "Ben",
  "location" => { "city" => "Chicago", "state" => "IL" },
  "status" => "Staying warm!"
}

Accessing Elements within Hashes

Unlike an array, the order of a hash doesn't matter.  We never care about the first thing in a hash - we want to know the value of a key in the hash.  For example, if we want to get the user's name, we use square brackets [ ] around the key:

name = user["name"]
puts name

To access values in a nested hash, we chain the keys together:

city = user["location"]["city"]
puts city

state = user["location"]["state"]
puts state

Modifying Hashes

Data is rarely static - it's frequently changing.  We can modify our hash by assigning a new value to a key:

user["status"] = "Writing some code."
puts user

user["location"]["city"] = "Evanston"
puts user

Hashes and Arrays

By combining hashes and arrays, we can pretty much represent any real-world data.  Let's see them together:

let user = {
  "name" => { "first" => "Ben", "last" => "Block" },
  "location" => { "city" => "Chicago", "state" => "IL" },
  "timeline" => [{ "status" => "Brrr!", "posted_at" => "9:00am" },
                 { "status" => "Coding.", "posted_at" => "10:00am" },
                 { "status" => "Lunch time.", "posted_at" => "12:00pm" }]
}

It takes a bit of digging to get to the data you want in these more complex objects:

let first_name = user["name"]["first"]
let first_status = user["timeline"][0]["status"]
puts "#{first_name}'s first post was #{first_status}"

Lab

Time for a lab to practice working with hashes. Instructions are in the file 4-hashes.rb in the labs directory.