-
Notifications
You must be signed in to change notification settings - Fork 4
Koans About Hashes
def test_creating_hashes
empty_hash = Hash.new
assert_equal Hash, empty_hash.class
assert_equal({}, empty_hash)
assert_equal 0, empty_hash.size
end
There are two ways to make a new hash; Hash.new
and {}
Both will have a default size of 0.
def test_hash_literals
hash = { :one => "uno", :two => "dos" }
assert_equal 2, hash.size
end
Hash size counts the number of key-value pairs.
def test_accessing_hashes
hash = { :one => "uno", :two => "dos" }
assert_equal "uno", hash[:one]
assert_equal "dos", hash[:two]
assert_equal nil, hash[:doesnt_exist]
end
If you want to get to a particular value in a hash, then you put the key inside the square brackets. If you search for a key that does not exist, it will return nil.
def test_accessing_hashes_with_fetch
hash = { :one => "uno" }
assert_equal "uno", hash.fetch(:one)
assert_raise(KeyError) do
hash.fetch(:doesnt_exist)
end
end
However, if you use the fetch
method (instead of square brackets) and search for a key that does not exist, it will raise a KeyError. So if you want to be alerted when a key does not exist in the hash, you may want to use fetch
def test_changing_hashes
hash = { :one => "uno", :two => "dos" }
hash[:one] = "eins"
expected = { :one => "eins", :two => "dos" }
assert_equal expected, hash
end
If you want to change a value within the hash, you use the square brackets around the key, and then use the single equal sign to assign the new value.
def test_hash_is_unordered
hash1 = { :one => "uno", :two => "dos" }
hash2 = { :two => "dos", :one => "uno" }
assert_equal true, hash1 == hash2
end
Because all keys in a hash must be unique, order is not important for a hash. If order is important to the information, you may want to use an array instead.
def test_hash_keys
hash = { :one => "uno", :two => "dos" }
assert_equal 2, hash.keys.size
assert_equal true, hash.keys.include?(:one)
assert_equal true, hash.keys.include?(:two)
assert_equal Array, hash.keys.class
end
You can access all the keys in a hash using the keys
method. Calling this method with return an array of all the keys in the hash. If you want to see if one particular key exists in the hash, you can chain the keys
and include?
methods.
def test_hash_values
hash = { :one => "uno", :two => "dos" }
assert_equal 2, hash.values.size
assert_equal true, hash.values.include?("uno")
assert_equal true, hash.values.include?("dos")
assert_equal Array, hash.values.class
end
Similar to the keys
method, there is a values
method that will return all the values of a hash in an array.
def test_combining_hashes
hash = { "jim" => 53, "amy" => 20, "dan" => 23 }
new_hash = hash.merge({ "jim" => 54, "jenny" => 26 })
assert_equal true, hash != new_hash
expected = { "jim" => 54, "amy" => 20, "dan" => 23, "jenny" => 26 }
assert_equal true, expected == new_hash
end
Hashes can be combined using the merge
method. If both hashes have the same key, the value from the hash passed as the argument to the merge
method will be used in the new hash.
def test_default_value
hash1 = Hash.new
hash1[:one] = 1
assert_equal 1, hash1[:one]
assert_equal nil, hash1[:two]
hash2 = Hash.new("dos")
hash2[:one] = 1
assert_equal 1, hash2[:one]
assert_equal "dos", hash2[:two]
end
If you do not specify a default value for a new hash, as seen in hash1, the default will always be nil. If you want to set a default value, you can do so when you instantiate the hash by passing in a value as an argument, as they did in hash2.
def test_default_value_is_the_same_object
hash = Hash.new([])
hash[:one] << "uno"
#So it turns out what is happening is that it is asking the hash if it have the key :one. It doesn't, so it shovels the "uno" into the empty default hash.
hash[:two] << "dos"
#As it doesn't have a key ":two" either, it shovels the "dos" into the default has. So, when we ask for things that don't exist again, we get the default array. Which by now is uno and dos.
assert_equal ["uno","dos"], hash[:one]
assert_equal ["uno","dos"], hash[:two]
assert_equal ["uno","dos"], hash[:three]
assert_equal true, hash[:one].object_id == hash[:two].object_id
end
Here a new hash is instantiated with a default value of an empty hash. When we look for keys we have not defined (:one and :two) it takes that default array and pushes (<<
) the "uno" and "dos" into that array. Each time we are changing the same default array, not creating new ones.
def test_default_value_with_block
hash = Hash.new {|hash, key| hash[key] = [] }
hash[:one] << "uno"
hash[:two] << "dos"
assert_equal ["uno"], hash[:one]
assert_equal ["dos"], hash[:two]
assert_equal [], hash[:three]
end
Here because we are making the default value a block, so when we push "uno" onto hash[:one], we are creating key-value pair where :one is the key and value is an array containing the string "uno."