Ruby Hash

Initialize a Ruby Hash

# Create an Empty Hash
{}
Hash.new

{:la => "Los Angeles", :sf => "San Francisco"}     # Use Symbol for key
{la: "Los Angeles", sf: "San Francisco"}           # Ruby 1.9

Hash[:la, "Los Angeles", :sf, "San Francisco"]

{"la" => "Los Angeles", "sf" => "San Francisco"}   # Use String for key

Initialize a nil hash method parameter

def m1(list)
  list ||= {}                                      # same as l = l.nil? ? {} : l

  list.length                                      # Above initialization allows call with list = nil

end

m1 nil
m1 ({:a=>"a",:b=>"b"})

Access a Ruby Hash

city = {:la => "Los Angeles", :sf => "San Francisco"}

city[:la]                     # "Los Angeles"
city[:wrong_city]             # nil

city ||= {}                   # Initiate a empty hash if not present
city[:sf] = "San Francisco"

city.store(:boston,"boston")  # city[:boston]="boston"

city.keys                     # [:la, :sf]: return all keys
city.values                   # ["Los Angeles", "San Francisco"]: return all values

city.fetch(:la)               # "Los Angeles"
city.fetch(:wrong_city)       # Raise key not found error (IndexError)

city.fetch(:wrong_city, "City Not Found")  # If key not found, return "City Not Found"
city.fetch(:wrong_city) {|x| x.to_s }      # If key not found, run the code block.
                                           # :wrong_city.to_s returned

city.values_at(:wrong_city, :sf, :la)      # [nil, "San Francisco", "Los Angeles"]

city.assoc :la                             # Ruby 1.9: [:la, "Los Angeles"]

# Reverse lookup
city.index "Los Angeles"                   # :la
city.rassoc "Los Angeles"                  # Ruby 1.9: [:la, "Los Angeles"]

Ruby Hash Enumerator

# la:Los Angeles sf:San Francisco
city.each {|key, value| print "#{key}:#{value} "}
city.each_pair {|key, value| print "#{key}:#{value} "}

city.each_key {|key| print key }            # lasf
city.each_value {|value| print value }      # Los AngelesSan Francisco

city.shift[1] while not city.empty?         # "Los Angeles"
                                            # "San Francisco"
# [[:la, "Los Angeles"]]
city.select {|key,value| value=="Los Angeles" }

Ruby Hash Default Value

To return a default value when index is not found for a Ruby Hash

#Default
city[:wrong_city]   # nil

# Change the default when the hash value is not found
h = Hash.new("Wrong Location")
h.default = "Some other value"

h[:not_found]       # "Some other value"

Return default value by a code block if a Hash index is not found

# If value not found in the hash
# Use the code block to return the default value of that entry
h = Hash.new {|h,key| key}

Ruby Hash Function

Merge Ruby Hash

alpha1 = {:a => "a", :b => "b", :c => "c"}
alpha2 = {:b => "b", :c => "c1", :d => "d"}

# {:c=>"c1", :a=>"a", :d=>"d", :b=>"b"}
# If both sets contain the same key, alpha2 value will be used
alpha1.merge(alpha2)
alpha1 = {:a => "a", :b => "b", :c => "c"}
alpha2 = {:b => "b", :c => "c1", :d => "d"}

# Use code block to resolve collision
# The code block use alpha1 value if both sets contain the same key
alpha1.merge(alpha2) {|key,v1,v2| v1 }     # {:c=>"c", :a=>"a", :d=>"d", :b=>"b"}

Delete Ruby Hash

alpha = {:a => "a", :b => "b", :c => "c", :d => "d" }

alpha.delete :d
alpha.delete :d      # nil
alpha.delete(:d) {|x| raise IndexError} # Raise IndexError if :d is not found

alpha.reject! {|key,value| key==:c}     # Remove :c
alpha.delete_if {|key,value| key==:b}   # Remove :b

alpha.clear         # Empty: {}

Invert Ruby Hash

city.invert        # Swap keys and values
                   # {"Los Angeles" => :la, "San Francisco" => :sf }

Flatten Ruby Hash

city.flatten     # v1.9 only [:la, "Los Angeles", :sf, "San Francisco"]

Ruby Hash Condition Testing

city = {:la => "Los Angeles", :sf => "San Francisco"}

# Does hash has key :la
city.has_key?(:la)
city.key?(:la)
city.include?(:c)
city.member?(:d)

# Does hash has value "Los Angeles"
city.value?("Los Angeles")
city.has_value?("Los Angeles")

Notes

  • If a hash is the last parameter, { } can be omitted
    puts({:la => "Los Angeles", :sf => "San Francisco"})
    
    puts :la => "Los Angeles", :sf => "San Francisco"
    
  • The key object MUST implement eql? and hash method
  • If the key object value is changed, the key will hash to a different location and therefore will not locate the hash value. To solve this:
    • Use a duplicate copy for the key and do not change the duplicate copy OR
    • Call the freeze method on the key
      • When String is used as key, Ruby will use a duplicate copy automatically