<Ruby> ハッシュ
ハッシュ
複数のオブジェクトをまとめる箱のようなもので、ハッシュオブジェクトともいう。
公式docでは、「任意の種類のオブジェクト(キー)から任意の種類のオブジェクト(値)への関連づけを行うことができる」と記載されており、以下のように継承されている。
BasicObject > Kernel > Object > Enumerable > Hash
ハッシュは以下のように表され、キーにはシンボルが使用される。
上記は次のように書き換えることができる。
{ name: "山田", address: "東京" }
※値には配列を入れることもできる。
シンボル
オブジェクトの一種で、ハッシュのキーではラベルのように使われている。
またシンボルと文字列はハッシュクラスのto_sメソッドとto_symメソッドでそれぞれ変換ができる。
p "名前".to_sym # => :名前 p :name.to_s # => "name"
変数への代入と値の取得
ハッシュは変数に代入できる。
変数に代入すると変数[キー]で値を取得することができる。
user = { name: "山田花子", address: "東京" } p user # => {:name=>"山田花子", :address=>"東京"} p user[:name] # => "山田花子"
存在しないキーを選択するとnilが返る。
defaultメソッドを使用することで、存在しないキーを選択した時に返る値が設定できる。
user = { name: "山田花子" } p user[:address] # => nil user.default = 0 p user[:address] # => 0
キーの一意性について
ハッシュはすでに存在しているキーを使用することはできない。 もし存在しているキーを=メソッドで追加しようすると代入されてしまう。
キーと値の組の追加
を使用した=インスタンスメソッドを使用して追加する。
※他にもstoreメソッドが同義で存在する
self[key] = value -> object
といったように定義されているため、
=の左辺:自分自身(以下の例だと変数user)との内部に追加したい組のキー
=の右辺:入力したい値
とするとhashオブジェクトが返る、ということがわかる。
ちなみに=でインスタンスメソッドなので、下の
user[:address] = "東京"
で返るのは"東京"ということになる。
user = { name: "山田花子" } p user # => {:name=>"山田花子"} user[:address] = "東京" p user # => {:name=>"山田花子", :address=>"東京"}
ハッシュを結合
mergeメソッドはハッシュ同士を結合し、hashオブジェクトを返す。
merge(*others) -> Hash
リファレンスマニュアルには「selfとothersのハッシュの内容を順番にマージ(統合)した結果を返す」と記載されている。
user_name = { name: "山田花子" } user_address = { address: "東京" } p user_name # => {:name=>"山田花子"} p user_address # => {:address=>"東京"} user = user_name.merge(user_address) p user # => {:name=>"山田花子", :address=>"東京"}
キーと値の組を削除
deleteメソッドは指定したキーと値の組み合わせを削除する。
user = { name: "山田花子", address: "東京" } p user # => {:name=>"山田花子", :address=>"東京"} user.delete(:address) p user # => {:name=>"山田花子"}
ハッシュの要素の繰り返し処理
配列同様eachメソッドを使用する。
ハッシュの要素が入る変数はキーは左、値は右に入るようになっている。
変数名は特に決まっていないが、key、valueがわかりやすいので基本的にはこれが使用されている。
user = { name: "山田花子", address: "東京" } # do ~ end形式の場合 user.each do |key, value| p "#{key}は#{value}" end # {}形式の場合 user.each { |key, value| p "#{key}は#{value}" } # 結果 "nameは山田花子" "addressは東京"
キーだけを取り出す
each_keyメソッドを使用する。
user = { name: "山田花子", address: "東京" } # do ~ end形式 user.each_key do |key| p "#{key}" end # {}形式 user.each_key { |key| p "#{key}" } # 結果 "name" "address"
値だけを取り出す
each_valueメソッドを使用する。
user = { name: "山田花子", address: "東京" } # do ~ end形式 user.each_value do |value| p "#{value}" end # {}形式 user.each_value { |value| p "#{value}" } # 結果 "山田花子" "東京"
mapについて
hashもEnumerableクラスのメソッドを継承しているのでmapが使用できる。
が、戻り値が配列になるのでto_hメソッドでハッシュに変換する必要がある。
そしてリファレンスマニュアルを確認してわかるようにhashクラスではmap!は継承されていないので使えない。
salary = { rookie: 20, mid_level: 25, veteran: 30 } # valueの配列が出力される p salary.map { |key, value| value*2 } # => [40, 50, 60] # Arrayクラスの[]特異メソッドでkeyとvalueを一つの配列に入れているため、配列 in 配列になっている p salary.map { |key, value| [key, value * 2] } # => [[:rookie, 40], [:mid_level, 50], [:veteran, 60]] # 配列で返ってきているのでto_hでハッシュに変換 p salary.map { |key, value| [key, value * 2] }.to_h # => {:rookie=>40, :mid_level=>50, :veteran=>60}
特異メソッド[]は、引数を要素として持つ配列を生成する。
参考文献、引用文献
class Hash (Ruby 3.0.0 リファレンスマニュアル)