A Hash is a collection of key-value pairs. To add, fetch, modify, and delete a value from a Hash, you refer to it with a unique key.
While an Array is indexed by Integers only, a Hash is keyed by any object -- Strings, Integers, etc.
In other programming languages, a Hash might be known as an 'associative array', 'dictionary', or 'HashMap'.
The empty Hash is just two curly braces:
{}
To create a Hash with a single key-value pair, place the pair inside the curly braces, separated by a hash-rocket =>
:
{ 'name' => 'john' }
In this example, 'name'
is the key and 'john'
is the corresponding value.
NOTE: One space after the opening curly brace {
, before the closing curly brace }
, and around the hash-rocket =>
is considered good style.
Multiple key-value pairs are further separated by a comma and a space:
{ 'name' => 'john', 'age' => 40 }
In this example, 'name'
and 'age'
are the keys. And 'john'
and 40
are their corresponding values.
When calling puts
on a Hash:
puts 'name' => 'john', 'age' => 40
NOTE: Ruby will fail with a SyntaxError
if you use curly braces {}
.
It displays the following:
{"name"=>"john", "age"=>40}
NOTE: Ruby always uses double quotation marks when displaying Strings.
Similarly, when calling p
on this Hash:
p 'name' => 'john', 'age' => 40
NOTE: Again, Ruby will fail with a SyntaxError
if you use curly braces {}
.
It also displays the following:
{"name"=>"john", "age"=>40}
A Hash and an Array have many commonalities. For example, an Array can be assigned to a variable:
person = ['john', 40]
Similarly, a Hash can be assigned to a variable too:
person = { 'name' => 'john', 'age' => 40 }
An Array can receive a variety of methods:
person = ['john', 40]
person.size #=> 2
In this example, an Array with two elements is assigned to the person
variable.
Similarly, a Hash can receive a variety of methods too:
person = { 'name' => 'john', 'age' => 40 }
person.size #=> 2
In this example, a Hash with two key-value pairs is assigned to the person
variable.
A single element of an Array can be fetched by it's index:
person = ['john', 40]
person[0] #=> 'john'
Likewise, a single value of a Hash can be fetched by it's key:
person = { 'name' => 'john', 'age' => 40 }
person['name'] #=> 'john'
Fetching an element from an Array with a non-existent index returns nil
:
person = ['john', 40]
person[2] #=> nil
Likewise, fetching a value from a Hash with a non-existent key also returns nil
:
person = { 'name' => 'john', 'age' => 40 }
person['location'] #=> nil
Given an Array index, it's element can be reassigned:
person = ['john', 40]
person[0] = 'paul'
Likewise, given a Hash key, it's value can be reassigned:
person = { 'name' => 'john', 'age' => 40 }
person['name'] = 'paul'
Given an Array index, it's element can be deleted from the Array:
person = ['john', 40]
person.delete_at(0) #=> 'john'
person #=> [40]
NOTE: The element 40
is now at index 0
.
Likewise, given a Hash key, it's key-value pair can be deleted:
person = { 'name' => 'john', 'age' => 40 }
person.delete('name') #=> 'john'
person #=> { 'age' => 40 }
NOTE: The value 40
is still at key 'age'
.
Each element and index combination of an Array can be iterated over:
person = ['john', 40]
person.each_with_index do |element, index|
puts "#{element} at #{index}"
end
Which displays the following:
john at 0
40 at 1
Similarly, each key-value pair of a Hash can be iterated over:
person = { 'name' => 'john', 'age' => 40 }
person.each do |key, value|
puts "#{key}: #{value}"
end
Which displays the following:
name: john
age: 40
Even with some minor quirks, Hashes and Arrays are rather similar. However, there are a few major differences.
An Array is indexed by Integers only:
person = ['john', 40]
person[0] #=> 'john'
person[1] #=> 40
While a Hash is keyed by any object. For example, by Strings:
person = { 'name' => 'john', 'age' => 40 }
person['name'] #=> 'john'
person['age'] #=> 40
Or by Integers:
person = { 1 => 'john', 2 => 40 }
person[1] #=> 'john'
person[2] #=> 40
Or by a mixture of both Strings and Integers:
person = { 'name' => 'john', 2 => 40 }
person['name'] #=> 'john'
person[2] #=> 40
Though it's rarely done, a Hash can even be keyed by an Array or a Hash.
NOTE: It's extremely common for a Hash to be keyed by a Symbol -- another object type you'll see shortly.
An Array is ordered by the numerical value of each index, which always starts at 0
:
person = ['john', 40]
person.each_with_index do |element, index|
puts "#{element} at #{index}"
end
Which displays the following:
john at 0
40 at 1
On the other hand, a Hash is ordered by the insertion order of each the key-value pair:
person = { 'name' => 'john', 'age' => 40 }
person.each do |key, value|
puts "#{key}: #{value}"
end
Which displays the following:
name: john
age: 40
There are a variety of ways to add an element to an Array.
It can be pushed to the end of an Array by using either the push
method or shovel <<
operator:
person = ['john', 40]
person.push('paul') #=> ['john', 40, 'paul']
person << 72 #=> ['john', 40, 'paul', 72]
It can be unshifted to the beginning of an Array by using the unshift
method:
person = ['john', 40]
person.unshift('paul') #=> ['paul', 'john', 40]
And it can be inserted at a specific index of the Array with the insert
method:
person = ['john', 40]
person.insert(1, 'paul') #=> ['john', 'paul', 40]
All of these techniques make it easy for you to manage the order of the elements in an Array.
On the other hand, there is only one way to add a key-value pair to a Hash. And that is with the assignment =
operator:
person = { 'name' => 'john', 'age' => 40 }
person['friend'] = 'paul'
person #=> { 'name' => 'john', 'age' => 40, 'friend' => 'paul' }
In this example, the value 'paul'
was assigned to the 'friend'
key. Since the 'friend'
key didn't exist in the Hash, the key-value pair was then added to the end.
Two Arrays can be concatenated together, forming a new Array containing all the elements of both Arrays:
person = ['john'] + [40]
person #=> ['john', 40]
However, two Hashes cannot be concatenated together:
person = { 'name' => 'john' } + { 'age' => 40 }
# NoMethodError: undefined method `+' for {"name"=>"john"}:Hash
Instead, two Hashes can be merged together:
person = { 'name' => 'john' }.merge('age' => 40)
person #=> { 'name' => 'john', 'age' => 40 }
NOTE: A Hash used as a method argument does not need the curly braces {}
.
At first glace, merging looks just like concatenation. However, when both Hashes have the same key, the Hash inside the merge
method takes precedence:
person = { 'name' => 'john', 'age' => 40 }.merge('age' => 35)
person #=> { 'name' => 'john', 'age' => 35 }
In this example, both Hashes contain the 'age'
key. When merged together, the 'age' => 35
key-value pair overwrites the 'age' => 40
key-value pair. In other words, key-value pairs from the Hash inside the merge
method overwrite key-value pairs from the Hash receiving the method call.
What confusion i have had--its all gone now!!! ):