Ruby基礎復習(6) Hash
『パーフェクトRuby』p.179より。
まず基本的なとこで。
1hash = {hoge: 1, fuga: 2}
2
3hash.each do |key, val|
4 p "#{key}: #{val}"
5end # => "hoge: 1", "fuga: 2"
6
7hash.each_key do |key|
8 p key
9end # => "hoge", "fuga"
10
11hash.each_value do |val|
12 p val
13end # => "1", "2"
14
15hash[:hoge] = 3
16p hash # => {hoge: 3, fuga: 2}
17hash[:piyo] = 4
18p hash # => {hoge: 3, fuga: 2, piyo: 4}
19
20hash.delete(:piyo)
21hash # => {hoge: 3, fuga: 2}
22
23hash.empty? # => false
24hash.length # => 2
ハッシュの生成はHash[]
により偶数個の引数から行うこともできる。
1ary = ["hoge", 1, "fuga", 2]
2Hash[*ary] # => {hoge: 1, fuga: 2}
3
4ary = [["hoge", 1], ["fuga", 2]]
5Hash[ary] # => {hoge: 1, fuga: 2}
Arrayクラスと同様の#select
、#reject
、#keep_if
、#delete_if
操作が可能。
1hash = {hoge: 1, fuga: 2, piyo: 3}
2
3hash.select {|key, val| val.even? } # => {fuga: 2}
4p hash # => {hoge: 1, fuga: 2, piyo: 3}
5hash.select! {|key, val| val.even? } # => {fuga: 2}
6p hash # => {fuga: 2}
7
8hash = {hoge: 1, fuga: 2, piyo: 3}
9
10hash.reject {|key, val| val.even? } # => {hoge: 1, piyo: 3}
11p hash # => {hoge: 1, fuga: 2, piyo: 3}
12hash.reject! {|key, val| val.even? } # => {hoge: 1, piyo: 3}
13p hash # => {hoge: 1, piyo: 3}
14
15hash.select! {|key, val| val.even? } # => nil
16hash.keep_if {|key, val| val.even? } # => {hoge: 1, piyo: 3}
17hash.reject! {|key, val| val.even? } # => nil
18hash.delete_if {|key, val| val.even? } # => {hoge: 1, piyo: 3}
Hashの統合はHash#merge
を用いる。キーが重複する場合は、引数で渡されたハッシュの値で上書きされる。ブロックを引き渡している場合は、キー重複時の処理をブロックの中で定義できる。破壊的操作であるHash#merge!
はHash#update
とも書くことが出来る。
1a = {hoge: 1, fuga: 2}
2b = {hoge: 3, piyo: 4}
3a.merge(b) # => {hoge: 3, fuga: 2, piyo: 4}
4p a # => {hoge: 1, fuga: 2}
5
6a.merge!(b) {|key, a_val, b_val|
7 a_val + b_val
8} # => {hoge: 4, fuga: 2, piyo: 4}
9p a # => {hoge: 4, fuga: 2, piyo: 4}
キーと値の取得に関して。特に特定キーの存在確認については、Hash#has_key?
を用いる。通常のHash[]
による呼び出しだと、値が存在しない場合でもnilが返ってきてしまい、値がnilなのか、それとも存在していないのか区別がつかないため。あるいはHash#fetch
を用いれば、値が存在しない場合の返り値を指定できる。
1hash = {hoge: 1, fuga: 2, piyo: 3, hogehoge: nil}
2
3hash.keys # => [:hoge, :fuga, :piyo]
4hash.key(2) # => :fuga
5
6hash.values # => [1, 2, 3]
7hash.values_at(:fuga) # => [2]
8hash.values_at(:fuga, :piyo) # => [2, 3]
9
10hash[:hogehoge] # => nil
11hash[:foo] # => nil
12hash.has_key?(:foo) # => false
13# 以下すべてhas_key?と同義
14hash.member?(:foo)
15hash.include?(:foo)
16hash.key?(:foo)
17
18hash.fetch(:foo) # => nil
19hash.fetch(:foo, "error") # => "error"
20hash.fetch(:foo){|key| "#{key} not exists"} # => "foo not exists"
21
22hash.has_value?(3) # => true
23hash.value?(3) # => true
Hashにはデフォルト値の概念があり、Hash#new
の引数に与えた値が、存在しないキーを参照したときの返り値となる(デフォルトはnil)。ここで指定した値はすべて同一オブジェクトであり、破壊的操作をする場合などは注意が必要。またHash#default=
やHash#default_proc=
により、既存のHashオブジェクトに対してもデフォルト値の変更が可能。
1hash = Hash.new("null")
2hash[:foo] # => "null"
3
4hash.default = "undefined"
5hash[:foo] # => "undefined"
6default = hash.default
7default.reverse!
8hash[:foo] # => "denifednu"
9
10hash.default_proc = ->(hash, key) {"Key: #{key} not exists"}
11hash[:foo] # => "Key: foo not exists"
ハッシュ変換系のメソッド。
1hash = {hoge: 1, fuga: 2}
2
3hash.invert # => {1: hoge, 2: fuga}
4hash.to_a # => [[:hoge, 1], [:fuga, 2]]
5hash.sort # => [[:fuga, 2], [:hoge, 1]]