弊社には技術に関する質問チャンネルがある。Ruby力がないため恥をしのんで質問したら、たくさんの知見を含む回答がもらえたので、忘れないように書いておく。
## 問題
一番深いhashのvalueを[]で囲った文字列にしたい。
irb(main):015:1* hash = {3=>{0=>"テキスト"}, irb(main):016:1* 4=>{0=>"5"}, irb(main):017:1* 5=>{0=>"tawara@example.com"}, irb(main):018:1* 6=>{0=>"2022-08-01"}, irb(main):019:1* 7=>{0=>"テキストエリア"}, irb(main):020:1* 8=>{0=>"ruby"}, irb(main):021:1* 9=>{0=>"ウルトラマン|ゼットン|ゴジラ"}, irb(main):022:1* 10=>{0=>"オードリー"}, irb(main):023:1* 11=>{0=>"ラジオ"}, irb(main):024:1* 12=>{0=>"ポム", 1=>"リト", 2=>"ナガシマ"}, irb(main):025:1* 13=>{0=>"hoge", 3=>"huga", 4=>"hoo"}, irb(main):026:1* 14=>{0=>"大三元|四暗刻", 3=>"小四喜|大四喜", 4=>"地和|天和"}, irb(main):027:0> 15=>{0=>"雑種"}}
↓
irb(main):029:0> hash => {3=>{0=>"[テキスト]"}, 4=>{0=>"[5]"}, 5=>{0=>"[tawara@example.com]"}, 6=>{0=>"[2022-08-01]"}, 7=>{0=>"[テキストエリア]"}, 8=>{0=>"[ruby]"}, 9=>{0=>"[ウルトラマン|ゼットン|ゴジラ]"}, 10=>{0=>"[オードリー]"}, 11=>{0=>"[ラジオ]"}, 12=>{0=>"[ポム]", 1=>"[リト]", 2=>"[ナガシマ]"}, 13=>{0=>"[hoge]", 3=>"[huga]", 4=>"[hoo]"}, 14=>{0=>"[大三元|四暗刻]", 3=>"[小四喜|大四喜]", 4=>"[地和|天和]"}, 15=>{0=>"[雑種]"}}
## 回答1
hash を配列[k,v]に変換、vをさらに[kk, vv]に変換する処理のなかでvvに[]をつけてからhashに戻し、さらにhashに戻すやり方。
irb(main):032:0> hash.map{ |k, v| [k, v.map{ |kk, vv| [kk, "[#{vv}]"] }.to_h] }.to_h => {3=>{0=>"[テキスト]"}, 4=>{0=>"[5]"}, 5=>{0=>"[tawara@example.com]"}, 6=>{0=>"[2022-08-01]"}, 7=>{0=>"[テキストエリア]"}, 8=>{0=>"[ruby]"}, 9=>{0=>"[ウルトラマン|ゼットン|ゴジラ]"}, 10=>{0=>"[オードリー]"}, 11=>{0=>"[ラジオ]"}, 12=>{0=>"[ポム]", 1=>"[リト]", 2=>"[ナガシマ]"}, 13=>{0=>"[hoge]", 3=>"[huga]", 4=>"[hoo]"}, 14=>{0=>"[大三元|四暗刻]", 3=>"[小四喜|大四喜]", 4=>"[地和|天和]"}, 15=>{0=>"[雑種]"}}
## 回答2
rails6で追加された #deep_transform_valuesメソッドを使う。めっちゃわかりやすい。
https://api.rubyonrails.org/classes/Hash.html#method-i-deep_transform_values
irb(main):033:0> hash.deep_transform_values { |v| "[#{v}]" } => {3=>{0=>"[テキスト]"}, 4=>{0=>"[5]"}, 5=>{0=>"[tawara@example.com]"}, 6=>{0=>"[2022-08-01]"}, 7=>{0=>"[テキストエリア]"}, 8=>{0=>"[ruby]"}, 9=>{0=>"[ウルトラマン|ゼットン|ゴジラ]"}, 10=>{0=>"[オードリー]"}, 11=>{0=>"[ラジオ]"}, 12=>{0=>"[ポム]", 1=>"[リト]", 2=>"[ナガシマ]"}, 13=>{0=>"[hoge]", 3=>"[huga]", 4=>"[hoo]"}, 14=>{0=>"[大三元|四暗刻]", 3=>"[小四喜|大四喜]", 4=>"[地和|天和]"}, 15=>{0=>"[雑種]"}}
ちなみにRuby3ならhash.deep_transform_values { "[#{_1}]" }
と書ける。引数が少なくておしゃれ。
## 回答3
ruby2.4から追加された#transform_valuesメソッドを見つけたので、こうも書ける。
irb(main):034:1* hash.values.each do |v| irb(main):035:1* v.transform_values{|vv| "[#{vv}]"} irb(main):036:0> end => [{0=>"テキスト"}, {0=>"5"}, {0=>"tawara@example.com"}, {0=>"2022-08-01"}, {0=>"テキストエリア"}, {0=>"ruby"}, {0=>"ウルトラマン|ゼットン|ゴジラ"}, {0=>"オードリー"}, {0=>"ラジオ"}, {0=>"ポム", 1=>"リト", 2=>"ナガシマ"}, {0=>"hoge", 3=>"huga", 4=>"hoo"}, {0=>"大三元|四暗刻", 3=>"小四喜|大四喜", 4=>"地和|天和"}, {0=>"雑種"}]
やまびこのように知見が返ってくるのは組織で働く喜びですね。
(了)