Ruby / Railsで、key-value なオブジェクトから値を取得するイディオム
環境
Ruby 2.5.1
Ruby on Rails 5.0.5
きっかけ
Rails を触っていると、Hash から特定の key の値だけ取得したい時がある
hash = { key1: "value1", key2: "value2", key3: "value3" }
hash.slice(:key1, :key2)
=> {:key1=>"value1", :key2=>"value2"}
違う、そうじゃない
おれは値だけがほしいんだ
hash.slice(:key1, :key2)
=> {:key1=>"value1", :key2=>"value2"}
# ↓ 本当はこうしたい
=> ["value1", "value2"]
> hash.extract(:key1, :key2)
NoMethodError: undefined method `extract` for {:key1=>"value1", :key2=>"value2", :key3=>"value3"}:Hash
...
> hash.pluck(:key1, :key2)
TypeError: no implicit conversion of Symbol into Integer
...
> hash.attributes(:key1, :key2)
NoMethodError: undefined method `attributes` for {:key1=>"value1", :key2=>"value2", :key3=>"value3"}:Hash
...
んーなんだっけ?
といつも自分でもわからなくなるので、似たような目的のメソッドとか書き方を自分用としてまとめました
ちなみに、さきほどの問題に対しての回答は
hash.values_at(:key1, :key2)
=> ["value1", "value2"]
でした
Hash
hash = { key1: "value1", key2: "value2", key3: "value3" }
# 値だけ
hash.values_at(:key1, :key2)
=> ["value1", "value2"]
# Hash として
hash.slice(:key1, :key2) # ruby 2.5.0 で ActiveSuport から輸入
=> {:key1=>"value1", :key2=>"value2"}
Hash[]
> hashes = [{ key1: "value1-1", key2: "value2-1"}, { key1: "value1-2", key2: "value2-2"}]
# 値だけ
hash.pluck(:key1) # rails 5.0 からの Enumerable 拡張
=> ["value1-1", "value1-2"]
# Hash として
hashes.map { |h| h.slice(:key1) }
=> [{:key1=>"value1-1"}, {:key1=>"value1-2"}]
ApplicationRecord
message = Message.take
# 値だけ
user.attributes.values_at("title", "text") # #attributes は Hash を返すので、キーの指定が文字列である必要がある
or
user.slice(:title, :text).values # Ruby 1.9 から Hash は順序を保存するようになったのでこれでも大丈夫
=> ["タイトル1", "内容1"]
# Hash として
user.slice(:title, :text)
=> {"title"=>"タイトル1", "text"=>"内容1"} # with_indifferent_access されて帰ってくるので、文字列でもシンボルでもアクセス可能
ActiveRecord::Associations
users = User.take(2)
# 値だけ
users.pluck(:title, :text)
=> [["タイトル1", "内容1"], ["タイトル2", "内容2"]]
# Hash として
users.map { |u| u.slice(:title, :text) }
=> [{"title"=>"タイトル1", "text"=>"内容1"}, {"title"=>"タイトル2", "text"=>"内容2"}]
hash = { key1: "value1", key2: "value2", key3: "value3" }
# 値だけ
hash.values_at(:key1, :key2)
=> ["value1", "value2"]
# Hash として
hash.slice(:key1, :key2) # ruby 2.5.0 で ActiveSuport から輸入
=> {:key1=>"value1", :key2=>"value2"}
> hashes = [{ key1: "value1-1", key2: "value2-1"}, { key1: "value1-2", key2: "value2-2"}]
# 値だけ
hash.pluck(:key1) # rails 5.0 からの Enumerable 拡張
=> ["value1-1", "value1-2"]
# Hash として
hashes.map { |h| h.slice(:key1) }
=> [{:key1=>"value1-1"}, {:key1=>"value1-2"}]
ApplicationRecord
message = Message.take
# 値だけ
user.attributes.values_at("title", "text") # #attributes は Hash を返すので、キーの指定が文字列である必要がある
or
user.slice(:title, :text).values # Ruby 1.9 から Hash は順序を保存するようになったのでこれでも大丈夫
=> ["タイトル1", "内容1"]
# Hash として
user.slice(:title, :text)
=> {"title"=>"タイトル1", "text"=>"内容1"} # with_indifferent_access されて帰ってくるので、文字列でもシンボルでもアクセス可能
ActiveRecord::Associations
users = User.take(2)
# 値だけ
users.pluck(:title, :text)
=> [["タイトル1", "内容1"], ["タイトル2", "内容2"]]
# Hash として
users.map { |u| u.slice(:title, :text) }
=> [{"title"=>"タイトル1", "text"=>"内容1"}, {"title"=>"タイトル2", "text"=>"内容2"}]
message = Message.take
# 値だけ
user.attributes.values_at("title", "text") # #attributes は Hash を返すので、キーの指定が文字列である必要がある
or
user.slice(:title, :text).values # Ruby 1.9 から Hash は順序を保存するようになったのでこれでも大丈夫
=> ["タイトル1", "内容1"]
# Hash として
user.slice(:title, :text)
=> {"title"=>"タイトル1", "text"=>"内容1"} # with_indifferent_access されて帰ってくるので、文字列でもシンボルでもアクセス可能
users = User.take(2)
# 値だけ
users.pluck(:title, :text)
=> [["タイトル1", "内容1"], ["タイトル2", "内容2"]]
# Hash として
users.map { |u| u.slice(:title, :text) }
=> [{"title"=>"タイトル1", "text"=>"内容1"}, {"title"=>"タイトル2", "text"=>"内容2"}]
おまけ
似たようなメソッドがいっぱいあるぞ!
Hash#extract!
最初に間違えたやつのBANメソッド
何故か #extract
は存在しない
動作は #slice!
と同様
hash = { key1: "value1", key2: "value2", key3: "value3" }
hash.extract!(:key1, :key2)
=> {:key1=>"value1", :key2=>"value2"}
hash
=> {:key3=>"value3"}
Hash#except
#slice
の逆
特定のキーとその値を除外したい時に使える
hash = { key1: "value1", key2: "value2", key3: "value3" }
hash.except(:key3)
=> {:key1=>"value1", :key2=>"value2"}
Hash#fetch_values
#values_at
と似たような挙動をするメソッド
キーが見つからなければ KeyError
が発生する(#values_at
はnil
が返る)
ブロックを渡すと KeyError
の代わりに、その評価値が返る
hash = { key1: "value1", key2: "value2", key3: "value3" }
hash.fetch_values(:key1, :key2)
=> ["value1", "value2"]
hash.fetch_values(:key1, :key3)
KeyError: key not found: :key3
hash.fetch_values(:key1, :key3) { :not_found }
=> ["value1", :not_found]
Hash#assoc
Hash のキーを指定すると、引っかかった key-value の配列を返す
キーの指定は1つのみ
元々は、多次元配列に対して要素を取り出すのが目的な感じに見える(Arrayでも使えるし)
{ key1: "value1", key2: "value2" }.assoc(:key1)
=> [:key1, "value1"]
[[:key1, "value1"], [:key2, "value2"]].assoc(:key1)
=> [:key1, "value1"]
ちなみに、rassocというメソッドもあり、こちらはキーではなく値を引数に指定する
Author And Source
この問題について(Ruby / Railsで、key-value なオブジェクトから値を取得するイディオム), 我々は、より多くの情報をここで見つけました https://qiita.com/3nan3/items/702e46d43dbc9a613756著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .