RubyのArray(配列)とHash(連想配列)入門
Chef の Cookbook を書いたり読んだりする上で、Array(配列) と Hash(連想配列)で混乱される方が多いのではないでしょうか。プログラマな方には常識だそうですが、普段コードを書かないインフラエンジニアの方が Chefを理解していく際に結構な壁になることが多いようです。わたしもそうでした。
自分自身のメモ代わりにまとめたいと思います。
Array(配列) とは
Arrayは、イメージしやすく言うと複数のValue(値)が入っている入れ物です。順番(添字)をつけてValue(値)を管理します。順番は1からではなく、0から始まります。
# Array family_array を定義
family_array = [ "sazae", "masuo", "tarao" ]
# Array family_array からValue(値)を取り出す
puts family_array[0] # sazae と表示
puts family_array[1] # masuo と表示
puts family_array[2] # tarao と表示
Hash(連想配列) とは
ArrayはValue(値)を管理するために添字を使いますが、Hashは添字の代わりにKeyを使います。KeyとValueのペアは "=>"(ハッシュロケット) で表現します。
Keyは数字と違いなんらかの意味を持つので、コードが読みやすくなるという利点があります。下のサンプルコードを見てください。なんとなく、sazaeが妻で、mazuoが夫で、taraoが子供であることがコードを呼んでいる人に伝わりますよね。
# Hash family_hash を定義
family_hash = { "tsuma" => "sazae", "otto" => "masuo", "kodomo" => "tarao" }
# Hash family_hash から値を取り出す
puts family_hash["tsuma"] # sazae と表示
puts family_hash["otto"] # masuo と表示
puts family_hash["kodomo"] # tarao と表示
Arrayは[]で囲む、Hashは {}で囲む
大切なことなのでもう一度いいます。Arrayは[]で囲んで、Hashは {}で囲みます。大切です。
# Array は []で囲む。
family_array = [ "sazae", "masuo", "tarao" ]
# Hash は {}で囲む。
family_hash = { "tsuma" => "sazae", "otto" => "masuo", "kodomo" => "tarao" }
Hash の Symbol に注意
RubyのHashで混乱しやすいところは、HashのKeyに、String(文字列)とSymbolの両方使えるところです。StringもSymbolも人間から見ると、文字に見えるのですが、文法(リテラル)や内部処理の仕方が異なります。異なるので、混乱しやすいのです。
ものすごくざっくりいうと、Keyを " "
や ' '
で囲むのがString、接頭辞 :
がつくのがSymbolです。下のサンプルコード hash1とhash2はほぼおなじHashです。
# Keyを String で定義
hash_string = { "tsuma" => "sazae", "otto" => "masuo", "kodomo" => "tarao" }
# 値を取り出し
puts hash_string['tsuma'] # "sazae" と表示
puts hash_string['otto'] # "masuo" と表示
puts hash_string['kodomo'] # "tarao" と表示
# Keyを Symbol で定義
hash_symbol = { :tsuma => "sazae", :otto => "masuo", :kodomo => "tarao" }
# 値を取り出し
puts hash_string[:tsuma] # "sazae" と表示
puts hash_string[:otto] # "masuo" と表示
puts hash_string[:kodomo] # "tarao" と表示
更にややこしいことに、HashのKeyにSymbolを使う場合、KeyとValueの紐付けに =>
(ハッシュロケット)を使わず以下のようなシンプルな表記が可能になります。
記載はシンプルになって見やすいのですが、この表記法を知らない人には混乱のタネになります。また、あくまでも紐付けの表記が変わるだけで、値を取り出す際のリテラルは変わらないことにご注意ください。
# Keyを Symbol で定義 その2
hash_symbol = { tsuma: "sazae", otto: "masuo", kodomo: "tarao" }
# 値を取り出し
puts hash_string[:tsuma] # "sazae" と表示
puts hash_string[:otto] # "masuo" と表示
puts hash_string[:kodomo] # "tarao" と表示
Symbol の特徴
- Symbol とは、Ruby が内部でメソッド名などの識別に使っている数値で、任意の文字列に対して異なった値が割り当てらる。
- Symbol は、Symbolクラスのインスタンスとして実装されている
- 使い勝手と可読性は文字列と同程度で、実行が速いので、Symbolのほうがよい(らしい)
Symbol と String の違い
Symbol は文字列と同じような感覚で用いることができる。ただし、等値性に関して、異なることに注意。
- == は値が等しい場合に真となり、
- equal? はインスタンスが同じ場合に真となる。
試してみる。
↓文字列の場合、値は等しくても、別のインスタンスとして認識されている
mojiretu1 = "mojiretu"
mojiretu2 = "mojiretu"
puts mojiretu1 == mojiretu2 #=> true
puts mojiretu1.equal?(mojiretu2) #=> false
Symbolの場合、値もインスタンスも同じ。
symbol1 = :symbol
symbol2 = :symbol
puts symbol1 == symbol2 #=> true
puts symbol1.equal?(symbol2) #=> true
Symbol 使用上の注意
Symbol は _ 以外の記号は使えない
# これはエラーになる
#hash5 = { first-element: "sazae", second-element: "masuo" }
# _ (アンダーバー)だけ使える
hash5 = { :first_element => "sazae", :second_element => "masuo" }
puts hash5[:first_element] # sazae と表示
# 文字列ハッシュキーが文字列の場合は - も使える
hash6 = { "first-element" => "sazae", "second-element" => "masuo" }
puts hash6["second-element"] # masuo と表示
参考/引用: Hash から文字列でもシンボルでも値を取り出す
参考/引用: Rubyのややこしい配列とハッシュとシンボルについて整理してみた
参考/引用: Ruby 2.2 で {"Arbitrary Key": "value"} が出来るようになった話
参考/引用: Ruby のシンボル
Hash と Array の繰り返し文を整理する
(1) Array の繰り返し
puts "(1) Array の繰り返し"
array1 = [ "sazae", "masuo", "tarao" ]
#配列.each do |変数|
# 実行する処理1
# 実行する処理2
#end
array1.each do |namae|
puts namae
end
(2) Hash Symbol の繰り返し
puts "(2) Hash Symbol の繰り返し"
hash2 = { :first => "sazae", :second => "masuo", :third => "tarao" }
#連想配列.each do |キー, バリュー|
# 実行する処理1
# 実行する処理2
#end
hash2.each do |key, value|
puts "key = #{key}"
puts "value = #{value}"
end
(3) Hash String の繰り返し
puts "(3) Hash String の繰り返し"
hash3 = {
"1.1.1.1" => "example1.com",
"2.2.2.2" => "example2.com",
"3.3.3.3" => "example3.com"
}
hash3.each do |key, value|
puts "key = #{key}"
puts "value = #{value}"
end
(4) Hash の Value を 更に Hash(String Key)にして繰り返し
puts "(4) Hash の Value を 更に Hash(String Key)にして繰り返し"
hash4 = {
"1.1.1.1" => { "hostname" => "example1.com", "comment" => "hoge1" },
"2.2.2.2" => { "hostname" => "example2.com", "comment" => "hoge2" },
"3.3.3.3" => { "hostname" => "example3.com", "comment" => "hoge3" }
}
hash4.each do |key, value|
puts "key = #{key}"
puts "value = #{value["hostname"]}"
puts "comment = #{value["comment"]}"
end
(5) Hash の Value を 更に Hash(String Symbol)にして繰り返し
puts "(5) Hash の Value を 更に Hash(String Symbol)にして繰り返し"
hash5 = {
"1.1.1.1" => { hostname: "example1.com", comment: "hoge1" },
"2.2.2.2" => { hostname: "example2.com", comment: "hoge2" },
"3.3.3.3" => { hostname: "example3.com", comment: "hoge3" }
}
hash5.each do |key, value|
puts "key = #{key}"
puts "value = #{value[:hostname]}"
puts "comment = #{value[:comment]}"
end