Skip to content
Katie Walsh edited this page Jun 24, 2015 · 1 revision
  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."