[Ruby]どうしても配列の中身のハッシュを平坦化させたい
はじめに
配列とハッシュが混合したものを扱う際に、少々手こずったのでメモ程度に書き起こしておく。
結果的に少々泥臭さのあるコードとなってしまった気がするので、より自然で簡潔なものがあれば、ご指摘していただけると助かります。
配列の中のハッシュを平坦化
今回躓いていたのは、配列の中のハッシュの平坦化
どうにかして、①の配列を②の配列にしたい。
# ①の配列
[
[{"id"=>1}, {"name"=>"Bob", "gender"=>"m", "birthday"=>"2010/01/01"}],
[{"id"=>5}, {"name"=>"Tom", "gender"=>"m", "birthday"=>"2011/11/01"}],
[{"id"=>8}, {"name"=>"Alice", "gender"=>"w", "birthday"=>"2012/02/01"}]
]
# ②の配列
[
[{"id"=>1, "name"=>"Bob", "gender"=>"m", "birthday"=>"2010/01/01"}],
[{"id"=>5, "name"=>"Tom", "gender"=>"m", "birthday"=>"2011/11/01"}],
[{"id"=>8, "name"=>"Alice", "gender"=>"w", "birthday"=>"2012/02/01"}]
]
要するに配列の中身のハッシュを平坦化?というか一つのハッシュにするという作業。
そもそもの目的
そもそもなぜそんなことをする必要が出てくるのかという話から。
ids
とdetails
という2つの配列がある。
ids = [
{ 'id' => 1 },
{ 'id' => 5 },
{ 'id' => 8 }
]
details = [
{
'name' => 'Bob',
'gender' => 'm',
'birthday' => '2010/01/01'
},
{
'name' => 'Tom',
'gender' => 'm',
'birthday' => '2011/11/01'
},
{
'name' => 'Alice',
'gender' => 'w',
'birthday' => '2012/02/01'
}
]
この2つの配列は1:1で対応していて、レスポンスで返す際には、これらをくっつけた状態で返したい。
※ id=1
はBob
の情報。id=5
はTom
の情報...
そして、最終的に得たい形は次のハッシュと配列の組み合わせであった。
※ count
はids
の数
{
"count"=>3,
"details"=> [
{"id"=>1, "name"=>"Bob", "gender"=>"m", "birthday"=>"2010/01/01"},
{"id"=>5, "name"=>"Tom", "gender"=>"m", "birthday"=>"2011/11/01"},
{"id"=>8, "name"=>"Alice", "gender"=>"w", "birthday"=>"2012/02/01"}
]
}
そのため、配列の中身のハッシュを平坦化させるという作業が必要になる。
行ったこと
zipメソッド
zipメソッドは自身の要素と、引数で与えた配列の要素を同じインデックス同士で組み合わせた配列を返す。
今回のように同じインデックス同士で1対1対応しているものにもってこいのメソッドである。
details_after_zip = ids.zip(details)
#=> [[{"id"=>1}, {"name"=>"Bob", "gender"=>"m", "birthday"=>"2010/01/01"}], [{"id"=>5}, {"name"=>"Tom", "gender"=>"m", "birthday"=>"2011/11/01"}], [{"id"=>8}, {"name"=>"Alice", "gender"=>"w", "birthday"=>"2012/02/01"}]]
ここで最初の方で述べた、「配列の中身のハッシュを平坦化したい」という話に繋がる。
次の方法で一応解決はした。
mergeメソッド
merge
メソッドは、2つのハッシュを統合するというもの。
bob_info = details_after_zip[0]
bob_info[0].merge(bob_info[1])
#=> {"id"=>1, "name"=>"Bob", "gender"=>"m", "birthday"=>"2010/01/01"}
このメソッドをループさせて利用する。
details_hash_flatten = details_after_zip.map do |d|
d[0].merge(d[1])
end
#=>[{"id"=>1, "name"=>"Bob", "gender"=>"m", "birthday"=>"2010/01/01"}, {"id"=>5, "name"=>"Tom", "gender"=>"m", "birthday"=>"2011/11/01"}, {"id"=>8, "name"=>"Alice", "gender"=>"w", "birthday"=>"2012/02/01"}]
これで準備は整ったので、当初の目的の形にする。
{
'count' => ids.size,
'detail' => details_hash_flatten
}
#=>{ "count"=>3, "detail"=>[ {"id"=>1, "name"=>"Bob", "gender"=>"m", "birthday"=>"2010/01/01"}, {"id"=>5, "name"=>"Tom", "gender"=>"m", "birthday"=>"2011/11/01"}, {"id"=>8, "name"=>"Alice", "gender"=>"w", "birthday"=>"2012/02/01"}] }
おわりに
merge
メソッドをループさせるという解決方法をとった。
しかし、もっと良い方法があったのかもしれない。
それこそ「配列の中身のハッシュを平坦化させる」といったものはあるのだろうか。
追記
自分で書いていて感じたことではあったのですが、添字の[0]とかはダサいし、あんまり良くはないので避けたいとのご指摘。
reduceメソッド(またはinject)を使用したら、よりクリーンな形に。
ids.zip(details).map { |a| a.reduce(&:merge) }
#=> [{"id"=>1, "name"=>"Bob", "gender"=>"m", "birthday"=>"2010/01/01"}, {"id"=>5, "name"=>"Tom", "gender"=>"m", "birthday"=>"2011/11/01"}, {"id"=>8, "name"=>"Alice", "gender"=>"w", "birthday"=>"2012/02/01"}]
こっちのが良いですね。
Author And Source
この問題について([Ruby]どうしても配列の中身のハッシュを平坦化させたい), 我々は、より多くの情報をここで見つけました https://qiita.com/Jwataru/items/c5d4b1c5a28f868ddab0著者帰属:元の著者の情報は、元の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 .