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

&gt;&gt; 連載の目次は [こちら！](http://qiita.com/prgseek/items/237d02be844534063f1d)

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


### ■ハッシュの作成
```ruby
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]}  # 空のハッシュ {} が作成される
```


### ■値の取得
```ruby
puts hash1["name"]            # 普通。
p    hash1["spec"]            # 存在しないキーを指定するとnilが返る
puts hash1.fetch("age")       # fetch でも取れるが...
puts hash1.fetch("arukai!")   # fetch は、存在しないキーだと例外が発生する
```

### ■値のセット
```ruby
hash1["name"] = "miro-sama"     # 普通。
hash1.store("color", "brown");  # storeメソッド
```

### ■要素数の取得
```ruby
puts hash1.length
puts hash2.size
```

### ■繰り返し処理
#### [each]
```ruby
hash1.each {|key, value|
  puts "%sは%sですっ！" % [key, value]
}
```

#### [each_key]
```ruby
hash1.each_key {|key| puts key}
```

#### [each_value]
```ruby
hash1.each_value {|val| puts val}
```


### ■要素の削除
```ruby
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                                         # ハッシュを空にする（破壊的）
```


### ■ハッシュの結合
```ruby
h1, h2 = {aa:11, bb:22}, {bb:33, cc:44}
h3 = h1.merge(h2)  # マージ。キーが重複する場合、あと勝ちで上書きされる。!を付けると破壊的
```

### ■デフォルト値の指定
```ruby
# すべての無効なキーに同じデフォルト値(ただし別インスタンス)を返す
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")」で指定した静的なデフォルト値しか取れないらしい
```

### ■ハッシュの複製
```ruby
hash8 = hash1                        # 単なる参照の代入
p hash9 = Hash(hash1)                # ハッシュからハッシュを作成（中身のオブジェクトは同じ）
p hash10 = hash1.dup                 # 浅いコピー
p Marshal.load(Marshal.dump(hash1))  # 深いコピー
```
※浅いコピーと深いコピーについては、配列の章を参照
http://qiita.com/prgseek/items/1871a9cd60ba00827e91


### ■ハッシュと配列の相互変換
#### ・ハッシュから配列
```ruby
# キーだけを配列として取り出す
p hash1.keys

# 値だけを配列として取り出す
p hash1.values

# to_a で変換
arr = {aa:"xx", bb:"yy"}.to_a
# [[:aa, "xx"], [:bb, "yy"]] ってなる。使いみちあるかな〜って思ったけど、後述のソートのところで使われてるな。
```

#### ・配列からハッシュ
```ruby
arr = ["miro", "abi", "chee", "kiji", "mii", "sirokuro"]
h = Hash[*arr]  # {"miro"=>"abi", "chee"=>"kiji", "mii"=>"sirokuro"} ってなる
```
※あと 配列の flatten や transpose メソッドを駆使して変換する方法があるみたいだけど、利用機会が限られてると思うので、ここでは扱わない



### ■ハッシュをソートする
```ruby
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にする。
1. キーの降順でソート。理屈は1.と同じ。
1. 値の昇順でソート。理屈は1.と同じで、こちらは sort_by を使って値の方を評価している
1. 値の降順でソート。以下同文...


### ■ハッシュのよく使いそうなメソッド
#### ・ハッシュが空かどうか
```ruby
p ({}.empty?)  # true
```

#### ・条件にあったキーバリューのみ抽出する
```ruby
h = {aa:99, bb:88, cc:77, dd:66, ee:55}
h2 = h.select {|key,value| value > 70 }  # !を付けると破壊的
```

#### ・値からキーを取得
```ruby
h = {aa:11, bb:22, cc:33}
p h.key(22)  # :bb
```

#### ・あるキーが存在するか？
```ruby
h = {aa:11, bb:22, cc:33}
p h.key?(:cc)  # include? とか同機能のメソッドがあるけど、これがシンプルだしわかりやすいな。
```

#### ・ある値が存在するか？
```ruby
h = {aa:11, bb:22, cc:33}
p h.value?(11)
```