STUDY MEMO

学習のメモ書き

<Ruby> ハッシュ

ハッシュ

複数のオブジェクトをまとめる箱のようなもので、ハッシュオブジェクトともいう。
公式docでは、「任意の種類のオブジェクト(キー)から任意の種類のオブジェクト(値)への関連づけを行うことができる」と記載されており、以下のように継承されている。
BasicObject > Kernel > Object > Enumerable > Hash
ハッシュは以下のように表され、キーにはシンボルが使用される。

Image from Gyazo

上記は次のように書き換えることができる。

{ 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 リファレンスマニュアル)

Rubyのmap, map!メソッドの使い方 | UX MILK

【Rails入門】mapメソッドを完全攻略!配列操作の基礎を学ぼう | 侍エンジニアブログ