ハッシュは別名連想配列とも言われ、
任意の値に任意の値を結び付けることができる
データ型である。分かりやすい利用例としては、
ある文字列から連想する別の値を保存する
が挙げられる。たとえば、
といった情報を保存するときに、"富士山" という文字列に直接 3776を結び付けられるのがハッシュである。
ハッシュは、配列と同じ感覚で利用できる。配列の添字が整数に限られてい たのに対し、ハッシュはどんな種類の値でも添字に利用できる。たとえば、 つぎの値段表を変数に格納する場合を考えよう。
これまでの知識では、配列変数に格納する。
配列
変数 fruits | |||
[0] | [1] | [2] |
[3] |
"りんご" | "みかん" | "いちご" | "梨" |
変数 price | |||
[0] | [1] | [2] |
[3] |
150 | 30 | 20 | 120 |
2つの変数fruits, price
を用意し、
fruits
には品名を、price
には単価を
それぞれ配列として格納している。
ハッシュを利用すると、品名に対して直接価格を結び付けることができる。
ハッシュ
変数 price | |||||||||||||||||||||||
|
このような関係をRubyプログラムにしてみよう。ハッシュを 利用した簡単なプログラムは以下のようになる。
price = Hash.new(0) price["りんご"] = 150 price["みかん"] = 30 price["いちご"] = 20 price["梨"] = 120
各行の働きは以下のとおり。
price = Hash.new(0)
変数 price
に空っぽのハッシュを代入する。
Hash.new
が新しい空のハッシュ構造を作成することを意味する。
Hash.new(0)
とすると、
ハッシュの値が登録されていないときのデフォルト値を0にする(後述)。
price["りんご"] = 150
price
の持つハッシュの "りんご"
に対応する値として 150
を代入している。
配列の場合、[]
の中に指定した整数のことを「添字」と呼んだが、
ハッシュの場合は key という。いっぽう、key
に結び付けられた値のことを value
という。つまり、
key == "りんご" ↓ value == 150
となる。「key "りんご" の value は 150である」と表現する。
price["みかん"] = 30
price["いちご"] = 20
price["梨"] = 120
これらも、price
の持つハッシュの key、
"みかん", "いちご", "梨"
それぞれに対し、value として
30, 20, 120
を代入している。
これらのハッシュの初期化は以下のように書いてもよい。
price = {"りんご" => 150, "みかん" => 30, "いちご" => 20, "梨" => 120}
このように、プログラムを書く段階でハッシュの初期値を入れる場合は
中括弧 {}
で括り、
「キー」 => 「値」
という組み合わせをカンマ(,)
で区切って列挙する。
price = { "りんご" => 150, "みかん" => 30, "いちご" => 20, "梨" => 120 }
のように見やすいように適当に改行を入れてもよい。
このようにして price
変数に入ったハッシュの値は、
配列変数と同じように []
で取り出すことができる。
price["みかん"] 30 price["梨"] 120
ハッシュの初期値を囲む括弧は中括弧 {}
だが、
ハッシュの値を取り出す時に使うのは大括弧 []
であることに
注意せよ。
実際にプログラムを動かしてみよう。
#!/usr/koeki/bin/ruby # coding: utf-8 price = Hash.new(0) price["りんご"] = 150 price["みかん"] = 30 price["いちご"] = 20 price["梨"] = 120 puts "りんご、みかん、いちご、梨、のどの値段を知りたいですか?" what = gets.chomp! cost = price[what] printf("%sは1個%d円です\n", what, cost) if cost == 0 printf("っていうか%sは売ってないんで...\n", what) end
上記プログラムを fruits.rb
という名前で保存し、
実行してみること。りんご、みかん、いちご、梨、を入れたり、
それ以外の名前を入れて何が返るか実験すること。
% ./fruits.rb りんご、みかん、いちご、梨、のどの値段を知りたいですか? りんご りんごは1個150円です
「りんご、みかん」などを入れるとき、 Shift+SPCで日本語をON/OFFして入力してもよいが、 マウスでコピー&ペーストすると楽である。 KTermに表示されたメッセージにマウスを合わせて左ボタンを ダブルクリックすると単語をコピーでき、真中ボタンをクリックすると ペーストできる。
ここまでのまとめ。
ハッシュの受け皿を作成するのは Hash.new
Hash.new(値)とすると、未定義のキーでアクセスした
場合のデフォルト値になる
あらかじめ値を持つハッシュをプログラム中に書くときは
{キー1 =>値1,キー2 =>値2,……
}
のように列挙する。
配列にデータを格納するときと同様、ハッシュに格納するときも最初からデー タの個数が決まっているわけではない。最初に空のハッシュを作成し、データを 入力するごとに値を格納していく。以下の例は県名と県庁所在地を順番に読み込 んでハッシュに格納するものである。
#!/usr/koeki/bin/ruby # coding: utf-8 pref = Hash.new # 新しいハッシュの生成 while true STDERR.print "都道府県名: " tdfk = gets if tdfk == nil break end tdfk.chomp! STDERR.print "都道府県庁所在地: " ofc = gets.chomp! pref[tdfk] = ofc end STDERR.print "読込終了\n" p pref # pを呼んでハッシュの値を全表示
実際に動かしてみよう。入力の終わりでは[C-d]をタイプする。
% ./pref.rb 都道府県名: 山形 都道府県庁所在地: 山形 都道府県名: 山梨 都道府県庁所在地: 甲府 都道府県名: 愛知 都道府県庁所在地: 名古屋 都道府県名: 神奈川 都道府県庁所在地: 横浜 都道府県名: 茨城 都道府県庁所在地: 水戸 都道府県名: [C-d]読込終了 {"愛知"=>"名古屋", "神奈川"=>"横浜", "山形"=>"山形", "茨城"=>"水戸", "山梨"=>"甲府"}
最初に示した果物の価格の例ではプログラム中に埋め込んでいた価格ハッシュを
CSVファイルから読み取るようにする。読み取るデータファイルは以下の
fruits.csv
とする。
りんご,150 みかん,30 いちご,20 梨,120
#!/usr/koeki/bin/ruby
# coding: utf-8
price = Hash.new(0)
open("fruits.csv", "r") do |f|
while x = f.gets
if /(.*),(\d+)/ =~ x then
#$1=品名 $2=価格 (いずれも最初は文字列)
price[$1] = $2.to_i # 価格を整数化
end
end
end
puts "りんご、みかん、いちご、梨、のどの値段を知りたいですか?"
what = gets.chomp!
cost = price[what]
printf("%sは1個%d円です\n", what, cost)
if cost == 0
printf("っていうか%sは売ってないんで...\n", what)
end
ハッシュには、key, value がペアで入っている。これを全て取り出すには
for
ループで2つの変数を使って順次取り出す。
たとえば、
yaoya = {"りんご" => 150, "みかん" => 30, "いちご" => 20, "梨" => 120}
と代入したとして、 keyとvalueを順に取り出す方法とその結果は以下のようになる。
for fruit, howmuch in yaoya do printf("当店の%sは%d円です\n", fruit, howmuch) end 当店のりんごは150円です 当店のいちごは20円です 当店のみかんは30円です 当店の梨は120円です
ハッシュに格納されているキーだけを取り出すには keys
メソッドを利用する。たとえば上記の果物リストのある yaoya
変数の値から、キーだけを取り出すと以下のようになる。
yaoya.keys ["りんご", "みかん", "いちご", "梨"]
これを利用して、ハッシュに備わっているキーの一覧を表示したい場合は 以下のようにすればよい。
#!/usr/koeki/bin/ruby
# -*- coding: utf-8 -*-
yaoya = {"りんご" => 150, "みかん" => 30, "いちご" => 20, "梨" => 120}
yaoya.keys.each do |k|
puts(k)
end
print("以上のうちどの値段を調べますか: ")
fruit = gets.chomp
if yaoya[fruit] then
printf("%sは%d円です。\n", fruit, yaoya[fruit])
else # デフォルト値設定なしなので見つからなければ nil
printf("残念ながら「%s」は取り扱っていません。\n", fruit)
end
以下のような実行結果となる。
./fruit-keys.rb りんご みかん いちご 梨 以上のうちどの値段を調べますか: いちご いちごは20円です。 ./fruit-keys.rb りんご みかん いちご 梨 以上のうちどの値段を調べますか: 柿 残念ながら「柿」は取り扱っていません。
実用的なプログラムでは、実行時にデータベースなどからハッシュを取得するので、 キーをプログラム中に列挙したりせず、ハッシュそのものから取り出すことになる。