Ruby における hash 操作の逆引きまとめ
Ruby の hash に関係する操作でよく使われるメソッドをまとめました。
用途別にグループ分けをしているので、逆引きとしてご覧ください。
※ 想定している ruby のバージョンは ruby 2.3.1p112 です。
要素を追加する
ハッシュに要素(キーと値のペア)を追加したい時は、下記のようなやり方があります。
一つずつ追加する
[]=
単純な要素追加の場合には []= を使うのが一般的です。
hash = {}
hash[:hoge] = 1
hash
# {:hoge=>1}
store
[]= の別名のメソッドとして store も使うことができます。
hash = {}
hash.store(:fuga, 2)
hash
# {:fuga=>2}
ハッシュに別のハッシュを加える
merge, merge!
merge を使うと、すでに存在するハッシュの要素をもう一つのハッシュに統合できます。
同じキーが存在した場合は、引数で与えたハッシュの値で上書きされます。
hash1 = { a: 1, b: 1 }
# {:a=>1, :b=>1}
hash2 = { b: 2, c: 2 }
# {:b=>2, :c=>2}
hash1.merge(hash2)
# {:a=>1, :b=>2, :c=>2}
merge! の場合はレシーバ自身が上書きされます。
## merge はレシーバ自身は変更しない hash1.merge(hash2) # {:a=>1, :b=>2, :c=>2} hash1 # {:a=>1, :b=>1} ## merge! はレシーバ自身が変更される hash1.merge!(hash2) # {:a=>1, :b=>2, :c=>2} hash1 # {:a=>1, :b=>2, :c=>2}
update
merge! の別名のメソッドとして update があります。
hash = { hoge: 1 }
# {:hoge=>1}
hash.update({ fuga: 2})
# {:hoge=>1, :fuga=>2}
hash
# {:hoge=>1, :fuga=>2}
値を検索する
特定の値が存在するか調べる
value?
特定の値が存在するかどうかを判定し、Boolean で返します。
hash = { name: 'Tom', age: 21 }
# {:name=>"Tom", :age=>21}
hash.value?('Tom')
# true
hash.value?('Bob')
# false
has_value?
value? の同名のメソッドとして has_value? があります。
hash = { name: 'Tom', city: 'Tokyo' }
# {:name=>"Tom", :city=>"Tokyo"}
hash.has_value?('Tokyo')
# true
hash.has_value?('Osaka')
# false
値の一覧を返す
values
ハッシュの中に値として存在しているものを配列で返します。
hash = { a: 1, b: 2, c: 3 }
# {:a=>1, :b=>2, :c=>3}
hash.values
# [1, 2, 3]
特定のキー(単一)に紐づく値を取り出す
[]
あるキーに紐づく値を参照する場合には [] を用いるのが一般的です。
hash = { hoge: 1 }
# {:hoge=>1}
hash[:hoge]
# 1
fetch
[] と同様に値を取り出すことができますが、該当のキーが存在しない場合に KeyError を返します。
hash = { hoge: 1 }
hash.fetch(:hoge)
# 1
hash.fetch(:fuga)
# KeyError: key not found: :fuga
第2引数を渡すことで、キーが存在しなかった場合のデフォルト値を設定することができます。
hash.fetch(:fuga) # KeyError: key not found: :fuga hash.fetch(:fuga, "NotFound") # "NotFound"
特定のキー(複数可)が持つ値を配列で返す
fetch_values
引数としてキーを可変長な引数として渡すことで、それらのキーが持つ値を配列で取得できます。
hash = { a: 1, b: 2, c: 3 }
# {:a=>1, :b=>2, :c=>3}
hash.fetch_values(:a, :c)
# [1, 3]
ネストした要素を参照する
dig
ruby 2.3 で追加された dig メソッドを使えば、ネストした要素を安全に取得できます。
hash = { a: { b: { c: 3 } } }
# {:a=>{:b=>{:c=>3}}}
hash[:a][:b][:c]
# 3
hash.dig(:a, :b, :c)
# 3
## []のチェーンだと、途中でキーがない場合にエラーになる
hash[:a][:not_b][:c]
# NoMethodError: undefined method `[]' for nil:NilClass
## dig の場合は途中でキーがない場合はエラーにならず nil が返る
hash.dig(:a, :not_b, :c)
# nil
特定の値(単一)に紐づく値を取り出す
特定の値を持つキーが存在する場合はそのキー名を返し、存在しない場合は nil を返します。
key
hash = { name: 'Tom', city: 'Tokyo' }
# {:name=>"Tom", :city=>"Tokyo"}
hash.key('Tokyo')
# :city
hash.key('Osaka')
# nil
キーを検索する
特定のキーが存在するか調べる
key?
特定のキーが存在するかどうかを判定し、Boolean で返します。
hash = { a: 1, b: 2, c: 3 }
# {:a=>1, :b=>2, :c=>3}
hash.key?(:b)
# true
hash.key?(:d)
# false
has_key?
key? の同名のメソッドとして has_key? があります。
hash = { a: 1, b: 2, c: 3 }
# {:a=>1, :b=>2, :c=>3}
hash.has_key?(:b)
# true
hash.has_key?(:d)
# false
キーの一覧を返す
keys
ハッシュの中に存在するキーを配列にして返します。
hash = { name: 'Tom', city: 'Tokyo' }
# {:name=>"Tom", :city=>"Tokyo"}
hash.keys
# [:name, :city]
繰り返し処理する
キーごとに処理をする
each_key
ハッシュ内に存在するキーをブロック変数にしてイテレーションを回します。
hash = { name: 'Tom', city: 'Tokyo', age: 21 }
# {:name=>"Tom", :city=>"Tokyo", :age=>21}
hash.each_key { |key| puts key }
# name
# city
# age
値ごとに処理をする
each_value
ハッシュ内に存在する値をブロック変数にしてイテレーションを回します。
hash = { name: 'Tom', city: 'Tokyo', age: 21 }
# {:name=>"Tom", :city=>"Tokyo", :age=>21}
hash.each_value { |value| puts value }
# Tom
# Tokyo
# 21
キーと値のペアで処理をする
each_pair
ハッシュ内に存在するキーと値の2つをブロック変数にしてイテレーションを回します。
hash = { name: 'Tom', city: 'Tokyo', age: 21 }
# {:name=>"Tom", :city=>"Tokyo", :age=>21}
hash.each_pair { |key, value| puts "key: #{key}, value :#{value}" }
# key: name, value: Tom
# key: city, value: Tokyo
# key: age, value: 21
その他の操作
キーと値を入れ替える
invert
ハッシュのキーと値を入れ替えたハッシュを生成します。
キーは一意性を担保する必要があるため、値が重複している状態で invert した場合は後ろのキーが残ります。
(Ruby 1.9 以降はキーにも順序が存在します)
hash = { A: "Tom", B: "Bob", C: "Green" }
# {:A=>"Tom", :B=>"Bob", :C=>"Green"}
hash.invert
# {"Tom"=>:A, "Bob"=>:B, "Green"=>:C}
## 同じ値がある状態で invert した場合は後ろのキーが採用される
price = { orange: 150, apple: 200, banana: 150 }
# {:orange=>150, :apple=>200, :banana=>150}
price.invert
# {150=>:banana, 200=>:apple}
特定の条件を満たす要素を削除する
delete
引数として渡したキーの要素を削除します。
レシーバは変更されたうえで、戻り値としては削除された要素の値が返ります。
hash = { A: "Tom", B: "Bob", C: "Green" }
# {:A=>"Tom", :B=>"Bob", :C=>"Green"}
hash.delete(:A)
# "Tom"
hash
# {"Bob"=>:B, "Green"=>:C}
delete_if
キーと値を引数にした繰り返しブロックを実行し、真となる要素のみを削除します。
price = { orange: 150, apple: 200, banana: 80 }
# {:orange=>150, :apple=>200, :banana=>80}
price.delete_if { |_, price| price > 100 }
# {:banana=>80}
price
# {:banana=>80}
keep_if
delete_if とは逆に、繰り返しブロックを実行して真となった要素のみを残します。
price = { orange: 150, apple: 200, banana: 80 }
# {:orange=>150, :apple=>200, :banana=>80}
price.keep_if { |_, price| price > 100 }
# {:orange=>150, :apple=>200}