ハッシュ

ハッシュとは

ハッシュは別名連想配列とも言われ、

任意の値に任意の値を結び付けることができる

データ型である。分かりやすい利用例としては、

ある文字列から連想する別の値を保存する

が挙げられる。たとえば、

といった情報を保存するときに、"富士山" という文字列に直接 3776を結び付けられるのがハッシュである。

ハッシュの特性

ハッシュは、配列と同じ感覚で利用できる。配列の添字が整数に限られてい たのに対し、ハッシュはどんな種類の値でも添字に利用できる。たとえば、 つぎの値段表を変数に格納する場合を考えよう。

  1. りんご・・・150円
  2. みかん・・・ 30円
  3. いちご・・・ 20円
  4. 梨・・・・・120円

これまでの知識では、配列変数に格納する。

配列

変数 fruits
[0][1][2] [3]
"りんご""みかん""いちご""梨"
変数 price
[0][1][2] [3]
1503020120

2つの変数fruits, priceを用意し、 fruitsには品名を、priceには単価を それぞれ配列として格納している。

ハッシュを利用すると、品名に対して直接価格を結び付けることができる。

ハッシュ

変数 price
"りんご"
150

"梨"
120
"いちご"
20
"みかん"
30

このような関係をRubyプログラムにしてみよう。ハッシュを 利用した簡単なプログラムは以下のようになる。

price = Hash.new(0)
price["りんご"] = 150
price["みかん"] = 30
price["いちご"] = 20
price["梨"]  = 120

各行の働きは以下のとおり。

これらのハッシュの初期化は以下のように書いてもよい。

price = {"りんご" => 150, "みかん" => 30,
         "いちご" => 20, "梨" => 120}

このように、プログラムを書く段階でハッシュの初期値を入れる場合は 中括弧 {} で括り、

「キー」 => 「値」

という組み合わせをカンマ(,) で区切って列挙する。

price = {
  "りんご" => 150,
  "みかん" => 30,
  "いちご" => 20,
  "梨" => 120
}

のように見やすいように適当に改行を入れてもよい。

このようにして price 変数に入ったハッシュの値は、 配列変数と同じように [] で取り出すことができる。

price["みかん"]
30
price["梨"]
120

ハッシュの初期値を囲む括弧は中括弧 {} だが、 ハッシュの値を取り出す時に使うのは大括弧 [] であることに 注意せよ。

実際にプログラムを動かしてみよう。

fruits.rb

#!/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に表示されたメッセージにマウスを合わせて左ボタンを ダブルクリックすると単語をコピーでき、真中ボタンをクリックすると ペーストできる。

ここまでのまとめ。

ハッシュへの値の追加手順

キーと値を別々に入力する例

配列にデータを格納するときと同様、ハッシュに格納するときも最初からデー タの個数が決まっているわけではない。最初に空のハッシュを作成し、データを 入力するごとに値を格納していく。以下の例は県名と県庁所在地を順番に読み込 んでハッシュに格納するものである。

pref.rb

#!/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 とする。

fruits.csv

りんご,150
みかん,30
いちご,20
梨,120

fruits-read.rb

#!/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
["りんご", "みかん", "いちご", "梨"]

これを利用して、ハッシュに備わっているキーの一覧を表示したい場合は 以下のようにすればよい。

fruit-keys.rb

#!/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
りんご
みかん
いちご
梨
以上のうちどの値段を調べますか: 
残念ながら「柿」は取り扱っていません。

実用的なプログラムでは、実行時にデータベースなどからハッシュを取得するので、 キーをプログラム中に列挙したりせず、ハッシュそのものから取り出すことになる。


本日の目次