>> 連載の目次は こちら!
■概要
- マップや連想配列に当たるもの
- キーにも値にも任意のオブジェクトを指定できるが、キーには一般的には文字列かシンボルを指定する
■ハッシュの作成
p hash1 = {"name" => "miro", "age" => 9, "address" => "Tokyo"} # 普通。
p hash2 = Hash["name" => "mike", "age" => "3", "address" => "Kyoto"] # Hashクラスの[]メソッドで作成。
p hash3 = {:addr => "kagura", :open => "AM10:00", :close => "PM23:00"} # キーにシンボルを使う
p hash4 = {addr: "kagura", open: "AM10:00", close: "PM23:00"}; # キーがシンボルならシンプルに書ける
p hash5 = {} # 空のハッシュ {} が作成される
p hash6 = Hash.new() # 空のハッシュ {} が作成される
p hash7 = Hash.new {|hash, key| hash[key]} # 空のハッシュ {} が作成される
■値の取得
puts hash1["name"] # 普通。
p hash1["spec"] # 存在しないキーを指定するとnilが返る
puts hash1.fetch("age") # fetch でも取れるが...
puts hash1.fetch("arukai!") # fetch は、存在しないキーだと例外が発生する
■値のセット
hash1["name"] = "miro-sama" # 普通。
hash1.store("color", "brown"); # storeメソッド
■要素数の取得
puts hash1.length
puts hash2.size
■繰り返し処理
[each]
hash1.each {|key, value|
puts "%sは%sですっ!" % [key, value]
}
[each_key]
hash1.each_key {|key| puts key}
[each_value]
hash1.each_value {|val| puts val}
■要素の削除
h = {aa:99, bb:88, cc:77, dd:66, ee:55}
h.delete(:cc) # キーを指定して削除(破壊的)
h.delete(:xx) { puts "無いものは消せませんな..." } # deleteはキーが存在しない場合の処理をブロック内に記述できる
h.delete_if {|key, value| value > 80} # ある条件に該当する要素を削除(破壊的)
h2 = h.reject {|key, value| value < 60}; # ある条件に該当する要素を削除(非破壊的)。!を付ければ破壊的
h.clear # ハッシュを空にする(破壊的)
■ハッシュの結合
h1, h2 = {aa:11, bb:22}, {bb:33, cc:44}
h3 = h1.merge(h2) # マージ。キーが重複する場合、あと勝ちで上書きされる。!を付けると破壊的
■デフォルト値の指定
# すべての無効なキーに同じデフォルト値(ただし別インスタンス)を返す
telno = Hash.new("現在使われておりません");
puts telno['old-friend']
# ブロックで処理してデフォルト値を決める
hash11 = Hash.new{|hash, key| key + "なんて無いよ!" }
puts hash11['xox']
# ブロックで処理してデフォルト値を決めて、保存しておく(同じキーならオブジェクトを再作成しない)
hash12 = Hash.new{|hash, key| hash[key] = key + "といえば今後はこれ" }
puts hash12['xox']
# fetch で値を取り出すときにデフォルト値を指定する
puts val = hash11.fetch("aru?", "まあ無いよねー")
# fetch のデフォルト値をブロックで返す
puts val = hash11.fetch("just-shoes") {|key| key + "がないときはそう言って!"}
# デフォルト値をあとから指定
telno.default = "この番号は永久欠番です!";
# 現在のデフォルト値を取得
puts telno.default
# 「xxx.default = ooo」または「Hash.new("xxx")」で指定した静的なデフォルト値しか取れないらしい
■ハッシュの複製
hash8 = hash1 # 単なる参照の代入
p hash9 = Hash(hash1) # ハッシュからハッシュを作成(中身のオブジェクトは同じ)
p hash10 = hash1.dup # 浅いコピー
p Marshal.load(Marshal.dump(hash1)) # 深いコピー
※浅いコピーと深いコピーについては、配列の章を参照
http://qiita.com/prgseek/items/1871a9cd60ba00827e91
■ハッシュと配列の相互変換
・ハッシュから配列
# キーだけを配列として取り出す
p hash1.keys
# 値だけを配列として取り出す
p hash1.values
# to_a で変換
arr = {aa:"xx", bb:"yy"}.to_a
# [[:aa, "xx"], [:bb, "yy"]] ってなる。使いみちあるかな〜って思ったけど、後述のソートのところで使われてるな。
・配列からハッシュ
arr = ["miro", "abi", "chee", "kiji", "mii", "sirokuro"]
h = Hash[*arr] # {"miro"=>"abi", "chee"=>"kiji", "mii"=>"sirokuro"} ってなる
※あと 配列の flatten や transpose メソッドを駆使して変換する方法があるみたいだけど、利用機会が限られてると思うので、ここでは扱わない
■ハッシュをソートする
h = {cc:99, aa:111, bb:55}
h2 = Hash[h.sort] # 1
h3 = Hash[h.sort.reverse] # 2
h4 = Hash[h.sort_by {|k,v| v}] # 3
h5 = Hash[h.sort_by {|k,v| -v}] # 4
- キーの昇順でソート。sort は to_a で配列化してsortして返すので、そこからHashにする。
- キーの降順でソート。理屈は1.と同じ。
- 値の昇順でソート。理屈は1.と同じで、こちらは sort_by を使って値の方を評価している
- 値の降順でソート。以下同文...
■ハッシュのよく使いそうなメソッド
・ハッシュが空かどうか
p ({}.empty?) # true
・条件にあったキーバリューのみ抽出する
h = {aa:99, bb:88, cc:77, dd:66, ee:55}
h2 = h.select {|key,value| value > 70 } # !を付けると破壊的
・値からキーを取得
h = {aa:11, bb:22, cc:33}
p h.key(22) # :bb
・あるキーが存在するか?
h = {aa:11, bb:22, cc:33}
p h.key?(:cc) # include? とか同機能のメソッドがあるけど、これがシンプルだしわかりやすいな。
・ある値が存在するか?
h = {aa:11, bb:22, cc:33}
p h.value?(11)