ハッシュを利用するためには、色々な構造のデータをハッシュ形式にうまく 保存していく方法と、あとでハッシュから key と value を取り出すための方法に慣れておく必要がある。いくつかの題材を 見ながら、ハッシュを効率的に利用するメソッドとその使い方を覚えていこう。
成績処理のデータで、国語以外の点を追加しよう。データは以下のとおりとする。
山田太郎 50 40 中町太郎 90 70 飯森花子 91 90 鶴岡一人 60 50 酒田三吉 52 80 三川一二三 12 75
ハッシュは、このような表形式のものを構造的に格納することに向いている。 どの行も、「氏名」、「国語得点」、「数学得点」の順に並んでいる。 表計算ソフト等での入力イメージが以下のようなものだとする。
name | ja | math |
---|---|---|
山田太郎 | 50 | 40 |
中町太郎 | 90 | 70 |
飯森花子 | 91 | 90 |
鶴岡一人 | 60 | 50 |
酒田三吉 | 52 | 80 |
三川一二三 | 12 | 75 |
このような場合、各行の一件の値の集合(レコードという)をそれぞれハッシュで表す。
name | ja | math |
山田太郎 | 50 | 40 |
name | ja | math |
中町太郎 | 90 | 70 |
name | ja | math |
飯森花子 | 91 | 90 |
name | ja | math |
鶴岡一人 | 60 | 50 |
name | ja | math |
酒田三吉 | 52 | 80 |
name | ja | math |
三川一二三 | 12 | 75 |
これらの各ハッシュを配列に格納する。 上記の例の場合は、以下のような「6個のハッシュを要素に持つ配列」 として表現できる。
[{"name"=>"飯森花子", "ja"=>91, "math"=>90}, {"name"=>"中町太郎", "ja"=>90, "math"=>70}, {"name"=>"鶴岡一人", "ja"=>60, "math"=>50}, {"name"=>"山田太郎", "ja"=>50, "math"=>40}, {"name"=>"酒田三吉", "ja"=>52, "math"=>60}, {"name"=>"三川一二三", "ja"=>12, "math"=>75} ]
このような構造で値を格納するプログラムは以下のようになる。
#!/usr/koeki/bin/ruby # coding: utf-8 require "./kprintf.rb" point = Array.new # 個別ハッシュを格納する全体配列 sum = Array.new(2,0) # sumは配列にする。要素2個、各初期値は0 ave = Array.new # aveも配列にする。 while yline = gets if /(\S+)\s+(\d+)\s+(\d+)/ =~ yline # 1個目の() (\S+)→氏名が入る # 2個目の() (\d+)→国語の得点が入る # 3個目の() (\d+)→数学の得点が入る name, ja, math = $1, $2.to_i, $3.to_i point << {"name" => name, "ja"=>ja, "math"=>math} sum[0] += ja # 国語 sum[1] += math # 数学 end end ave[0] = sum[0].to_f/point.length # 国語の平均点 ave[1] = sum[1].to_f/point.length # 数学の平均点 print "--氏名--------------+-国語-+-平均との差--+-数学-+-平均との差--\n" for i in point # i には、"name", "ja", "math" をキーとするハッシュが入って来る student = i["name"] # iのキー"name"に対応する値が氏名 kokugo = i["ja"] # iのキー"ja"に対応する値が国語の点 math = i["math"] # iのキー"math"に対応する値が数学の点 printf("%-20s %5d %5.1f %5d %5.1f\n", student, kokugo, kokugo-ave[0], math, math-ave[1]) end puts "-"*62 printf("%-20s %5.1f%s%5.1f\n", "平均点", ave[0], " "*15, ave[1])
このように、1単位のデータ(レコード)をハッシュとして表現し、 それを配列などに複数集めて処理することはしばしば用いられる。
ハッシュの初期宣言として
x = Hash.new
のように、デフォルト値を指定しなかった場合、存在しない key の
value を参照するとnil
が返る。
x["hoge"] # "hoge" というkeyは未登録
=> nil
ところがもし、
x = Hash.new(0)
のように、デフォルト値を指定した場合、存在しない key の value を参照すると、指定した値が返る。
x["hero"] # "hero" というkeyは未登録
=> 0
初期宣言として、Hash.new()
を利用した場合は
デフォルト値が指定できるが、{ }
を利用して
ハッシュの初期値を代入した場合は、デフォルト値は nil
となる。つまり、
x = { "りんご" => "apple", "みかん" => "orange", "いちご" => "strawberry" }
と初期値代入した場合、未登録keyのvalueを参照するとnil
となる。
x["梨"] # "梨" というkeyは未登録
=> nil
このようなときに、あとからデフォルト値を設定するには ハッシュに属する
メソッドである default=
を利用する。
x.default="わかりませーん"
すると、以下のようになる。
x["梨"] # "梨" というkeyは未登録 => "わかりませーん" x["りんご"] # "りんご" というkeyは登録されている => "apple"
配列の場合は、決まった長さ(要素数)のものを、決められた値で
埋めつくした初期配列を作ることができる。これには Array.new
を利用する。
Array.new(長さ)
Array.new(長さ, 初期値)
指定した 長さ の要素数を持つ配列を作成する。 初期値 を指定した場合には、全ての要素に その 初期値 を代入する。
たとえば、
Array.new(5, 0)
とすると、
[0, 0, 0, 0, 0]
という配列が作成される。初期値を指定せず、
Array.new(4)
などとした場合は、
[nil, nil, nil, nil]
のように、各要素の初期値が nil
の配列が作成される。
ハッシュと違い、配列には存在しない範囲の添字の値を参照したときの
デフォルト値は指定できない。範囲外の添字を指定したときの値は
nil
となる。