More on hashes => less the hash rocket
Oh, so apparently the hash rocket is no longer used in hashes in Ruby 1.9 or later. In my previous post, I wrote about hashes and arrays, so here's a little update with a few more tidbits.
The old syntax looked like this:
my_hash = {:key1=>"value1", :key2=>"value2", :key3=>"value3")
And the new syntax without the hash rocket (i.e. =>), looks like this:
my_hash = {key1: "value1", key2: "value2", key3: "value3")
Note that both of these are equivalent. In both examples, the keys are symbols and the values strings. In the case where you'd want your values to be symbols, the new syntax would seem a bit odd:
my_hash = {key1: :value1, key2: :value2, key3: :value3)
But I think it would still work. In any case, i don't know when that would be necessary.
A few things to remember about symbols vs. strings:
symbols cannot have spaces
symbols are often used as hash keys or for referencing method names
symbols are immutable (i.e. cannot be changed once created)
only one copy of a symbol exists at a given time; this saves memory and makes using symbols as hash keys slightly faster to process than using strings
strings can be converted into symbols with the .to_sym or .intern methods
symbols can be converted into strings with the .to_s method
.EACH_KEY AND .EACH_VALUE METHODS
In my last post, I said that calling the .each method on a hash requires two parameters |key,value|. That's not always true. You can use the .each_key or the .each_value method and only pass in one parameter |key| or |value|, respectively. For example, the following block:
pets = {cat: "Felix", dog: "Spot", fish: "Wanda"}
pets.each do |pet,name|
puts "I have a pet #{key}."
end
can be refactored to this:
pets = {cat: "Felix", dog: "Spot", fish: "Wanda"}
pets.each_key do |pet|
puts "I have a pet #{key}."
end
where I only need to pass in the key, not the value. The same could be done using the .each_value method.
In Ruby applications, you'll mostly likely find more complicated data structures with hashes and arrays nested within each other, rather than the simple ones you see when learning Ruby. It can be tricky when trying to access information a few levels into the nested structure but of course always follows a pattern. Let's take this example:
school = { :name => "Happy Funtime School",
:location => "NYC",
:instructors => [
{:name=>"Blake", :subject=>"being awesome" },
{:name=>"Ashley", :subject=>"being better than blake"},
{:name=>"Jeff", :subject=>"karaoke"}
],
:students => [
{:name => "Marissa", :grade => "B"},
{:name=>"Billy", :grade => "F"},
{:name => "Frank", :grade => "A"},
{:name => "Sophie", :grade => "C"}
]
}
This is a hash with a combination of nested hashes and arrays. Here's how to retrieve some of that nested info:
# if I want to change Frank's grade to an F (sorry, Frank)
# hash_name[key_4][index_of_value_4][key_4.2] = [new_value_4.2]
school[:students][2][:grade]="F"
# if I want to remove Billy from the student's array
# hash_name[key4].arraymethod(index)
# note the use of '()' instead of brackets in the array method
school[:students].delete_at(1)
# if I want to return Jeff's subject
# hash_name[key_3][index_of_value_3][key_3.2]
school[:instructors][2][:subject]
These still seem quite long and cumbersome. It's also not immediately obvious which information would be returned without the explanatory comments. I'm sure there's a better and quicker way to do this, but I have yet to figure that out.