Ruby Hash

Ruby 教學 9 – Ruby Hash Object 介紹

Ruby Hash object 類似 JavaScript 的 Map,都是由 key-value pair 組成。

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]]

6. 參考資料

Learn to Code with Ruby
Class: Hash (Ruby 3.1.2)

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top