Ruby Hash object 類似 JavaScript 的 Map,都是由 key-value pair 組成。
Table of Contents
1. 宣告 Ruby Hash Object
在宣告 Ruby Hash object 先來了解一下 Hash object 的特性:
- keys 和 values 可以由任意 object 組成
- keys 的值不可重複
- values 的值可以重複
- 在 Hash 中,key 後面接 => 來宣告要對應的 value
- 如果 key 是 Symbol,則可以將 :[symbol_name] => value 簡化成 [symbol_name]: value
因為 Symbol 的效能較 String 來得優異,因此常用來作為 Hash 的 keys
h1 = {:name => "Jimmy", :name => "Sam"}
# warning: key :name is duplicated and overwritten on line 1
h1 = {"name" => "Jimmy", :age => 25, :weight => 25}
# ok
h1 = {:name => "Jimmy", :age => 25}
h2 = {name: "Jimmy", age: 25}
p h1
# {:name => "Jimmy", :age => 25}
p h2
# {:name=>"Jimmy", :age=>25}
p h1 == h2
# true
1.1 Hash.new
可以用 Hash.new 宣告空的 Hash object,有給 argument 時,則指定不存在 key 的 value 時要回傳什麼東西:
h1 = Hash.new
p h1
# {}
p h1[:name]
# nil
h2 = Hash.new(false)
p h2
# {}
p h2[:name]
# false
1.2 Hash
可以用 Hash 直接宣告新的 Hash object:
h1 = Hash[]
p h1
# {}
h2 = Hash[[[:name, "Jimmy"], [:age, 25]]]
h3 = Hash[:name, "Jimmy", :age, 25]
h4 = {:name => "Jimmy", :age => 25}
h5 = {name: "Jimmy", age: 25}
p h2, h3, h4, h5
# {:name=>"Jimmy", :age=>25}
h6 = Hash[h5]
p h5
# {:name=>"Jimmy", :age=>25}
p h6
# {:name=>"Jimmy", :age=>25}
p h5.object_id
# 60
p h6.object_id
# 80
2. Hash Instance Methods I – 屬性
2.1 Hash []
可以用 .[] 後面加 argument 來取得 key 對應的 vlaue:
h1 = {name: "Jimmy", age: 25}
p h1.[](:name)
# "Jimmy"
p h1[:name]
# "Jimmy"
2.2 Hash fetch
.fetch 和用 [] 直接存取 value 類似,差別在於如果沒有這個 key 的話可以指定要回傳什麼值:
h1 = {name: "Jimmy", age: 25}
p h1[:name]
# "Jimmy"
p h1.fetch(:name)
# "Jimmy"
p h1[:address]
# nil
p h1.fetch(:address)
# Error! `fetch': key not found: :address
p h1.fetch(:address, "Key not exists")
# Key not exists
2.5 Hash length/size
用來回傳有幾個 key-value pairs,和 .size 的功用一樣:
h1 = {name: "Jimmy", age: 25}
p h1.length
p h1.size
2.6 Hash keys
將這個 Hash object 的所有 key 放到一個 Array object 後回傳:
h1 = {name: "Jimmy", age: 25, city: "Taipei"}
p h1.keys
# [:name, :age, :city]
2.7 Hash values
將這個 Hash object 的所有 value 放到一個 Array object 後回傳:
h1 = {name: "Jimmy", age: 25, city: "Taipei"}
p h1.values
# ["Jimmy", 25, "Taipei"]
2.8 Hash default
可以用來指定當存取沒有的 key 時要回傳什麼 value:
h1 = {name: "Jimmy", age: 25, city: "Taipei"}
h1.default = "cannot find the key"
p h1[:address]
# "cannot find the key"
2.9 Hash key?
用來判斷這個 Hash object 是否有某個 key:
h1 = {name: "Jimmy", age: 25, city: "Taipei"}
p h1.key?(:name)
# true
p h1.key?(:address)
# false
2.10 Hash value?
用來判斷這個 Hash object 是否有某個 value:
h1 = {name: "Jimmy", age: 25, city: "Taipei"}
p h1.value?("Jimmy")
# true
p h1.value?(30)
# false
3. Hash Instance Methods II – 操作 (不改變原 Object)
3.1 Hash merge
會合併兩個 Hash object,如果有重複的 key,會以 argument 中的 Hash object 的 value 為主:
h1 = {name: "Jimmy", age: 25, city: "Taipei"}
h2 = {address: "Xinyi Road"}
h3 = {name: "Sam", age: 30, city: "Taoyuan"}
p h1.merge(h2)
# {:name=>"Jimmy", :age=>25, :city=>"Taipei", :address=>"Xinyi Road"}
p h1.merge(h3)
# {:name=>"Sam", :age=>30, :city=>"Taoyuan"}
p h1
# {:name=>"Jimmy", :age=>25, :city=>"Taipei"}
3.2 Hash to_a
將 Hash object 轉換成二維陣列後回傳:
h1 = {name: "Jimmy", age: 25, city: "Taipei"}
p h1.to_a
# [[:name, "Jimmy"], [:age, 25], [:city, "Taipei"]]
4. Hash Instance Methods II – 操作 (會改變原 Object)
4.1 Add key value pair in Hash Object
直接用 [] 賦值即可在 Hash object 新增 key-value pair:
h1 = {name: "Jimmy", age: 25}
h1[:address] = "Taipei"
p h1
# {:name=>"Jimmy", :age=>25, :address=>"Taipei"}
4.2 Hash store
.store 和上述方法一樣,可以在 Hash object 新增 key-value pair,這個 method 一次只能新增一個 key-value pair,如果給超過 2 個 arguments 會報錯:
h1 = {name: "Jimmy", age: 25}
h1.store(:address, "Taipei")
p h1
# {:name=>"Jimmy", :age=>25, :address=>"Taipei"}
h1.store(:country, "Taiwan", :height, 183)
p h1
# Error! `store': wrong number of arguments (given 4, expected 2)
4.3 Hash delete
用來刪除 Hash object 的 key-value pair:
h1 = {name: "Jimmy", age: 25, city: "Taipei"}
h1.delete(:name)
p h1
# {:age=>25, :city=>"Taipei"}
5. Hash Instance Methods III – 包含 block
5.1 Hash each
用來遍歷 Hash object 的 key 和 value:
h1 = {name: "Jimmy", age: 25, city: "Taipei"}
h1.each do |key, value|
p "value of #{key} is #{value}"
end
# "value of name is Jimmy"
# "value of age is 25"
# "value of city is Taipei"
5.2 Hash each_key
用來遍歷 Hash object 的 key:
h1 = {name: "Jimmy", age: 25, city: "Taipei"}
h1.each_key do |key|
p "key is #{key}"
end
# "key is name"
# "key is age"
# "key is city"
5.3 Hash each_value
用來遍歷 Hash object 的 value:
h1 = {name: "Jimmy", age: 25, city: "Taipei"}
h1.each_value do |value|
p "value is #{value}"
end
# "value is Jimmy"
# "value is 25"
# "value is Taipei"
5.4 Hash select
用來過濾某些 key-value pair,只會留下回傳 true 的 key-value pair:
h1 = {name: "Jimmy", age: 25, city: "Taipei"}
h2 = h1.select do |key, value|
value.is_a?(Integer)
end
p h2
{:age=>25}
5.5 Hash reject
用來過濾某些 key-value pair,只會留下回傳 false 的 key-value pair:
h1 = {name: "Jimmy", age: 25, city: "Taipei"}
h2 = h1.reject do |key, value|
value.is_a?(Integer)
end
p h2
# {:name=>"Jimmy", :city=>"Taipei"}
5.6 Hash sort
會以 key 的字母順序 ( alphabetic ) 排序後以二維陣列回傳:
h1 = {Math: 100, Chinese: 95, English: 80}
p h1.sort
# [[:Chinese, 95], [:English, 80], [:Math, 100]]
p h1.sort { |a, b| b <=> a }
# [[:Math, 100], [:English, 80], [:Chinese, 95]]
5.7 Hash sort_by
可以指定要用 key 或是 value 的什麼條件排序:
h1 = {Math: 100, Chinese: 95, English: 80}
p h1.sort_by { |key, value| value }
# [[:English, 80], [:Chinese, 95], [:Math, 100]]