Help us understand the problem. What is going on with this article?

[Ruby入門] 07. ハッシュを扱う

More than 3 years have passed since last update.

>> 連載の目次は こちら!

■概要

  • マップや連想配列に当たるもの
  • キーにも値にも任意のオブジェクトを指定できるが、キーには一般的には文字列かシンボルを指定する

■ハッシュの作成

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
  1. キーの昇順でソート。sort は to_a で配列化してsortして返すので、そこからHashにする。
  2. キーの降順でソート。理屈は1.と同じ。
  3. 値の昇順でソート。理屈は1.と同じで、こちらは sort_by を使って値の方を評価している
  4. 値の降順でソート。以下同文...

■ハッシュのよく使いそうなメソッド

・ハッシュが空かどうか

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)
prgseek
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした