組み込みクラス: HashClass編

今日中にIOとTimeと正規表現がノルマ...

Hashの生成

ハッシュは通常の{key => value}による定義以外にも、配列のようなHash[key,value]が使える。

irb(main):001:0> a = Hash[:tokyo, "新宿",:kanagawa,"横浜",:ehime,"matsuyama"]
=> {:tokyo=>"新宿", :kanagawa=>"横浜", :ehime=>"matsuyama"}

Hash.newに引数をわたして、デフォルト値を設定しておくこともできる。

irb(main):002:0> a = Hash.new("default")
=> {}
irb(main):003:0> a[:tokyo]
=> "default"

Hash.newはブロックをとることもできるので、そこでデフォルト値を設定する方法もある。

irb(main):004:0> c = Hash.new{|hash,key| hash[key] = "default"}
=> {}
irb(main):005:0> c[:tokyo]
=> "default"

ハッシュオブジェクトを作ったあとで、defaultメソッドで指定する方法もある。

irb(main):006:0> x = Hash.new()
=> {}
irb(main):007:0> x[:tokyo]
=> nil
irb(main):008:0> x.default = "DEFAULT"
=> "DEFAULT"     
irb(main):009:0> x[:tokyo]
=> "DEFAULT"

ハッシュのキーや値を取得する

keys,values

それぞれ、ハッシュのキー一覧と値一覧を配列で返す。

irb(main):013:0> a = Hash[:tokyo, "新宿",:kanagawa,"横浜",:ehime,"松島"]
=> {:tokyo=>"新宿", :kanagawa=>"横浜", :ehime=>"松島"}
irb(main):014:0> a.keys
=> [:tokyo, :kanagawa, :ehime]
irb(main):015:0> a.values
=> ["新宿", "横浜", "松島"]

values_at

キーをメソッドの可変数引数として渡して、その値を配列で受け取る。

irb(main):016:0> a.values_at(:tokyo,:kanagawa)
=> ["新宿", "横浜"]

fetch

配列でも扱ったように、fetchは存在しないキーを指定するとエラーを起こす。 これを回避するには、2番目の引数を指定しておくか、ブロックで処理を決めておく。

irb(main):018:0> a.fetch(:oosaka,"なかった。")
=> "なかった。"
irb(main):019:0> a.fetch(:oosaka){p "ないよ"}
"ないよ"
=> "ないよ"

select

ブロックを指定して、各ハッシュの要素(or キー)がtrueになったものだけを含んだ、ハッシュを返す。

irb(main):020:0> a = Hash[:tokyo, "新宿",:kanagawa,"横浜",:ehime,"松島", :fukuoka, "博多", :hokkaido, "札幌"]
=> {:tokyo=>"新宿", :kanagawa=>"横浜", :ehime=>"松島", :fukuoka=>"博多", :hokkaido=>"札幌"}
irb(main):021:0> a.select{|key,value| key.to_s.length > 6}
=> {:kanagawa=>"横浜", :fukuoka=>"博多", :hokkaido=>"札幌"}

find_all

selectの返り値が配列になったバージョン。

irb(main):022:0> a.find_all{|key,value| key.to_s.length > 6}
=> [[:kanagawa, "横浜"], [:fukuoka, "博多"], [:hokkaido, "札幌"]]

ハッシュを変更する

delete破壊的

ハッシュのキーを指定して削除する。

reject 破壊的あり

破壊的メソッドreject!エイリアスdelete_ifである。 値を指定して削除する直接の方法はなく、rejectでブロックで渡しながら削除する値を選ぶことになる。

irb(main):023:0> a
=> {:tokyo=>"新宿", :kanagawa=>"横浜", :ehime=>"松島", :fukuoka=>"博多", :hokkaido=>"札幌"}
irb(main):024:0> a.delete_if{|key,value| value == "横浜"}
=> {:tokyo=>"新宿", :ehime=>"松島", :fukuoka=>"博多", :hokkaido=>"札幌"}

replace,clear 破壊的

Arrayと同じく丸ごと置きかえ・全削除

shift 破壊的

配列でもshifはpopやinsertと同じく破壊的なメソッドであるように、shiftは破壊的メソッドとして用意されている

irb(main):025:0> a.shift
=> [:tokyo, "新宿"]
irb(main):026:0> a
=> {:ehime=>"松島", :fukuoka=>"博多", :hokkaido=>"札幌"}

merge 破壊的あり

他のハッシュをマージする。破壊的メソッドmerge!エイリアスとしてupdateが用意されている。 重複するキーに対応するため、ブロックを渡して、どちらをバリューとして選ぶか選択することが可能になっている。

instance method Hash#merge (Ruby 2.6.0)

irb(main):026:0> a
=> {:ehime=>"松島", :fukuoka=>"博多", :hokkaido=>"札幌"}
irb(main):027:0> a.merge({:ehime => "宇和島", :hokkaido => "hakodate"}){|key,self_val,new_val| new_val}
=> {:ehime=>"宇和島", :fukuoka=>"博多", :hokkaido=>"hakodate"}
irb(main):028:0> a.merge({:ehime => "宇和島", :hokkaido => "hakodate"}){|key,self_val,new_val| self_val}
=> {:ehime=>"松島", :fukuoka=>"博多", :hokkaido=>"札幌"}

invert破壊的なし

キーとハッシュのいれかえ。破壊的メソッドが存在しない。

irb(main):028:0> a.merge({:ehime => "宇和島", :hokkaido => "hakodate"}){|key,self_val,new_val| self_val}
=> {:ehime=>"松島", :fukuoka=>"博多", :hokkaido=>"札幌"}
irb(main):029:0> a.invert
=> {"松島"=>:ehime, "博多"=>:fukuoka, "札幌"=>:hokkaido}
irb(main):030:0> a
=> {:ehime=>"松島", :fukuoka=>"博多", :hokkaido=>"札幌"}
irb(main):031:0> a.invert!
Traceback (most recent call last):
        2: from /home/pyons/.rbenv/versions/2.5.0/bin/irb:11:in `<main>'
        1: from (irb):31
NoMethodError (undefined method `invert!' for {:ehime=>"松島", :fukuoka=>"博多", :hokkaido=>"札幌"}:Hash
Did you mean?  invert)

ハッシュを調べる

key?

なぜか3つもエイリアスが存在する謎メソッド。 include?, member? (Hash) - Rubyリファレンス

キーが存在するか調べる。booleanの返り値。

has_key?include?memeber?エイリアス

value?

has_valueエイリアス

値が存在するか調べる。

each_pair 破壊的なし

ブロックにkeyとvalueを渡していき、ブロック内で処理を行う。eachエイリアスである。 因みにブロック内で代入をおこなって値を変えようとしても、変更は起こらない。

irb(main):036:0> a.each{|k,v| v = "観光地"}
=> {:ehime=>"松島", :fukuoka=>"博多", :hokkaido=>"札幌"}
irb(main):037:0> a
=> {:ehime=>"松島", :fukuoka=>"博多", :hokkaido=>"札幌"}

each_key, each_value

irb(main):034:0> a.each_key{|key|p key}
:ehime
:fukuoka
:hokkaido
=> {:ehime=>"松島", :fukuoka=>"博多", :hokkaido=>"札幌"}
irb(main):035:0> a.each_value{|key|p key}
"松島"
"博多"
"札幌"

配列に変換

to_a

HashはStringと異なり、配列に変換するメソッドが用意されている。

sort 破壊的なし

配列にしてソートする。また、ブロックに渡して、手動バブルソートも行える。 Arrayと異なり、返り値が同じ型でなくなってしまうため破壊的なメソッドがない。

irb(main):040:0> a
=> {:ehime=>"松島", :fukuoka=>"博多", :hokkaido=>"札幌"}
irb(main):041:0> a.sort!
Traceback (most recent call last):
        2: from /home/pyons/.rbenv/versions/2.5.0/bin/irb:11:in `<main>'
        1: from (irb):41
NoMethodError (undefined method `sort!' for {:ehime=>"松島", :fukuoka=>"博多", :hokkaido=>"札幌"}:Hash
Did you mean?  sort)