LoginSignup
0
0

More than 5 years have passed since last update.

【Ruby】 Object#tap と break でハッシュの追加更新

Posted at

はじめに

"hoge".tap { |str| str.reverse }
# => "hoge"
"hoge".tap { |str| break str.reverse }
# => "egoh"

Object#tap に渡すブロックの中で break すると、その引数を返すことができる。
このテクニックの活用方法はこれまでもいくつか研究されてきた。

自分もつい先日、コーディング中に tap break を使うタイミングを見つけたので、そのことについて書いていく。

やりたいこと

table = Hash.new
ary = ["aa", "aaa", "abcd", "bbbb", "ccc"]

ary.each do |val|
  key = val.size
  if table.has_key? key
    table[key] << val
  else
    table[key] = [val]
  end
end

table
# => {2=>["aa"], 3=>["aaa", "ccc"], 4=>["abcd", "bbbb"]}

キーに対応する値が配列となるハッシュがあり、入力されるデータを分類しハッシュに格納していく、という場面。
ここでは例として、入力されるデータは文字列、分類基準は文字列の長さとした。
素直に if を用いて書いたが、tap break を使えばもっと短くできるのではないかと思った。

group_by 使えば?

ary.group_by(&:size)
# => {2=>["aa"], 3=>["aaa", "ccc"], 4=>["abcd", "bbbb"]}

やりたいことはまさに group_by なのだが、いくつかの理由で今回は使用しない。
ひとつは ary は別々に順次入力されるという状況だったので、 group_by の結果を毎回マージするのが面倒くさいから。
もうひとつは、先ほどのサンプルコードでは省略しているが、追加する val に加工をする必要があったから。

tap break 最終案

ary.each do |val|
  key = val.size
  table[key].tap { |t| break table[key] = [] unless t } << val
end
table
# => {2=>["aa"], 3=>["aaa", "ccc"], 4=>["abcd", "bbbb"]}
  • table[key]nil である場合
    • ブロックの中身が戻り値となるので、
    • (table[key] = []) << val となる
  • table[key]nil でない場合
    • レシーバが戻り値となるので、
    • table[key] << val となる

Ruby2.5で tap の親戚みたいなメソッド yield_self が追加されたが、 ブロックの中身を選択的に捨てたり返したりできる tap 楽しいよね、という。

tap break じゃなくてもいいのでは?

まあ、はい。
or演算子のやつはスッキリしてて個人的にいいと思った。
table[key]nil のときだけ右辺が評価されるので。

ary = ["aa", "aaa", "abcd", "bbbb", "ccc"]

# 条件演算子、三項演算子 を用いる場合
table = Hash.new
ary.each do |val|
  key = val.size
  (table[key].nil? ? table[key] = [] : table[key]) << val
end
table
# => {2=>["aa"], 3=>["aaa", "ccc"], 4=>["abcd", "bbbb"]}

# or演算子を用いる場合
table = Hash.new
ary.each do |val|
  key = val.size
  (table[key] || table[key] = []) << val
end
table
# => {2=>["aa"], 3=>["aaa", "ccc"], 4=>["abcd", "bbbb"]}

おわりに

読みづらいので他の人が読むコードでは書かない方がいいと思った。

参考

0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0