71
62

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ChefTips: RubyのArray(配列)とHash(連想配列)入門

Last updated at Posted at 2016-12-13

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
71
62
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
71
62

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?