【Ruby学習記録】連想配列の基本的な扱い方
お題1:次の内容をハッシュで定義して1つの変数に代入し、その中のキーが age の要素を取り出して出力せよ
name が トム
age が 22
hobby が baseball
person = {
name: "トム",
age: 22,
hobby: "baseball",
}
puts person[:age]
===
$ ruby answer.rb
22
お題2:下記のハッシュを格納した変数 person に次の内容を実行せよ
キーが blood で値が B という要素を追加
キーが weight の値を 78 に変更
キーが country 要素を削除
person = {name: "ken", country: "japan", height: 191, weight: 80}
person = {
name: "ken",
country: "japan",
height: 191,
weight: 80
}
person[:blood] = "B"
person[:weight] = 78
person.delete(:country)
puts person
===
$ ruby answer.rb
{:name=>"ken", :height=>191, :weight=>78, :blood=>"B"}
お題1、2はいずれもハッシュの基本的な扱い方のおさらい。代入の仕方や参照・更新の仕方。
Ruby で連想配列(ハッシュ)を定義したい場合、2 パターンの表記の仕方がある模様。
1 つは PHP あたりと同じようにキー名を「文字列リテラル」で記述しアロー演算子で値を紐づける方法。
# 定義
hash = { 'キー文字列' => 値 , 'キー文字列' => 値 ... }
# 参照
hash['キー文字列']
# 更新
hash['キー文字列'] = 値
もう一つは「シンボル」表記を使う方法。
# 定義
hash = { キー文字列: 値 , キー文字列: 値 ... }
# 参照
hash[:キー文字列]
# 更新
hash[:キー文字列] = 値
注意が必要なのは、アロー演算子を使った場合とシンボルを使った場合では、参照の仕方も変わること。
Ruby の世界では、見た目上のキーの名称が同じように見えても、「文字列リテラル」と「シンボル」はまったく違うものとして扱われるので、ハッシュのキーを文字列リテラルで定義した場合は、その後も文字列リテラルでしかアクセスできないし、シンボル表記で定義した場合はシンボル表記でしかアクセスできない。
なので、person['name']
とperson[:name]
では、まったく違うものを指していることになる。
よくよく調べると、文字リテラルは String クラスのインスタンスで、シンボルは Symbol クラスのインスタンスということなので、まったくの別クラスという風に言われると、確かに'name'
と:name
はまったく別物になるのは理解できる。
お題3:下記のハッシュが代入された変数 hash から、値の USA を取り出して出力せよ
hash = {
sports: {
soccer: {
origin: "England"
},
volleyball: {
origin: "USA"
}
}
}
hash = {
sports: {
soccer: {
origin: "England"
},
volleyball: {
origin: "USA"
}
}
}
puts hash[:sports][:volleyball][:origin]
===
$ ruby answer.rb
USA
こちらは、Ruby のハッシュは階層を持てるよ、入れ子にできるよ、というお話。
# 参照
hash[:親キー名][:子キー名][:孫キー名]
といった具合に、[キー名]
を左から順に上位 → 下位とつなげて書いていく。
お題4:次のハッシュを代入した変数 user の各要素の値を全て小文字に変換した内容を別の変数に代入せよ
user = {first_name: "KaTo", last_name: "KeN"}
user = {
first_name: "KaTo",
last_name: "KeN"
}
result =
user.map do |key, value|
# result[key] = value.downcase
[key, value.downcase]
end.to_h
p result
===
$ ruby answer.rb
{:first_name=>"kato", :last_name=>"ken"}
これは、ハッシュで使える繰り返し系メソッドを使って対応する問題。
で、map メソッドは「繰り返し処理を行った結果を配列として返す」というものになる。
なので、ハッシュ専用のメソッドではないし、結果がハッシュで返ってくるわけでもない。
ただ、ハッシュに対して map メソッドを使った場合、キーと値それぞれをループ内変数(今回はkey
, value
)で受け取れるので、それらを使って処理をしている。
で、どう処理しているのかというと、キーはそのまま、値に対してdowncase
メソッドを使って小文字に変換し、[キー, 値]
の順で配列に格納している。
この処理を元のハッシュの「キー/値」のペア数分だけ繰り返して、さらに配列に格納したものが返ってくるのが、user.map do ~ end
の部分となる。
*この時点では[[:first_name, "kato"], [:last_name, "ken"]]
という、配列の入れ子の形になっている。
今回のお題は結果を「ハッシュ」で欲しいので、Array.to_h
のメソッドで、配列をハッシュに変換してresult
に代入している。
このお題の場合、user.map do ~ end
という、一見制御構文っぽい箇所があって、それにto_h
メソッドがつながっているので一瞬おかしく思える。(特に C とかから覚えた人間には)
だが、これは Ruby の場合map do ~ end
で map メソッドの一連の式という扱いになるので、map do ~ end.to_h
という書き方で map メソッドの戻り値に対して to_h メソッドがさらに使える、ということになる。
もちろん、このような表記の仕方が気持ち悪ければ、一旦配列の状態でresult
に格納しておき、result.to_h
としても大丈夫。
Discussion