LoginSignup
2
0

More than 3 years have passed since last update.

[Ruby]ネストされたHash(連想配列)をフラット(1階層)にする①

Last updated at Posted at 2020-01-15

最近の勉強で学んだ事を、ノート代わりにまとめていきます。
主に自分の学習の流れを振り返りで残す形なので色々、省いてます。
Webエンジニアの諸先輩方からアドバイスやご指摘を頂けたらありがたいです!

Arra(配列)とHash(連想配列)

ChefTips: RubyのArray(配列)とHash(連想配列)入門

Array(配列) とは

Arrayは、イメージしやすく言うと複数のValue(値)が入っている入れ物です。順番(添字)をつけてValue(値)を管理します。順番は1からではなく、0から始まります。

# Array family_array を定義
family_array = [ "sazae", "masuo", "tarao" ]      

Hash(連想配列) とは

ArrayはValue(値)を管理するために添字を使いますが、Hashは添字の代わりにKeyを使います。KeyとValueのペアは "=>"(ハッシュロケット) で表現します。
Keyは数字と違いなんらかの意味を持つので、コードが読みやすくなるという利点があります。下のサンプルコードを見てください。なんとなく、sazaeが妻で、mazuoが夫で、taraoが子供であることがコードを呼んでいる人に伝わりますよね。

# Hash family_hash を定義
family_hash = { "tsuma" => "sazae", "otto" => "masuo", "kodomo" => "tarao" }  

今回やりたい事

こんなネストされたHashがあるとします、これをフラット(1階層)にしていきます!
ネストがあるhashの、keyとvalueの取得について

これを

hash =
{:basic=>[:name, :gender, :birthday],
 :history=>
  [:primary, :clinic, :status, :age],
 :test=>
  [:cycle,
   :history_test,
   :culture_test,
   :math_test,
   {:score=>[], :history_score=>[], :culuture_score=>[], :math_score=>[]}
  ],
 :tarou_infomation=>[:house, :address,:favorite, {:levels=>[], :experience=>[]}],
 }

こうしたい!パターンです!

hash =
[
:name,
:gender,
:birthday,
:primary, 
:clinic, 
:status, 
:age,
:cycle,
:history_test,
:culture_test,
:math_test,
:score, 
:history_score, 
:culuture_score, 
:math_score,
:house, 
:address,
:favorite,
:levels, 
:experience
]

色々試してみる

キーだけを消してバリューの要素だけとる。
Rubyでハッシュオブジェクトからキーや値を取り出す方法【初心者向け】
ハッシュを配列に変換する

pry(main)> hash.values
=> [[:name, :gender, :birthday],
 [:primary, :clinic, :status, :age],
 [:cycle, :history_test, :culture_test, :math_test, {:score=>[], :history_score=>[], :culuture_score=>[], :math_score=>[]}],
 [:house, :address, :favorite, {:levels=>[], :experience=>[]}]]

次はこれをフラットに!
flattenメソッドを使用して配列を平坦化する。
flatten, flatten! (Array) - Rubyリファレンス

pry(main)> hash.values.flatten
=> [:name,
 :gender,
 :birthday,
 :primary,
 :clinic,
 :status,
 :age,
 :cycle,
 :history_test,
 :culture_test,
 :math_test,
 {:score=>[], :history_score=>[], :culuture_score=>[], :math_score=>[]},
 :house,
 :address,
 :favorite,
 {:levels=>[], :experience=>[]}]

よし!フラットにできたけどHashが〜

ちなみにeach_with_objectを使えば一発でできました。
Ruby: injectとeach_with_objectをうまく使い分ける

pry(main)> hash.each_with_object([]) {|(k, v), array| array.concat v}
=> [:name,
 :gender,
 :birthday,
 :primary,
 :clinic,
 :status,
 :age,
 :cycle,
 :history_test,
 :culture_test,
 :math_test,
 {:score=>[], :history_score=>[], :culuture_score=>[], :math_score=>[]},
 :house,
 :address,
 :favorite,
 {:levels=>[], :experience=>[]}]

これは配列の中に連想配列がネストされているので
連想配列には別の対処が必要です。

配列にしたいHashをインデックスで指定

pry(main)> hash.values.flatten[11]
=> {:score=>[], :history_score=>[], :culuture_score=>[], :math_score=>[]}

これをキーだけの配列にはできる

 pry(main)> hash.values.flatten[11].keys
=> [:score, :history_score, :culuture_score, :math_score]

ゴリ押しで新しい変数にhashの要素だけdelete_atメソッドで削除してkesで作成した配列をconcatメソッドで1つの配列に結合する方法もありますがあまりしたくない。
【Ruby】配列の要素を追加・削除
Rubyで複数の配列を1つの配列に結合するために色々やってみた

しかも、そこそこ記述が多くなりそうなのでメソッドにするか〜
という事で次回は、Hash(連想配列)をフラット(1階層)にする記述をメソッドにしていきます!
[Ruby]ネストされたHash(連想配列)をフラット(1階層)にする②

参考記事

扱いにくい階層の深いHashをフラット(1階層)にする
how to permit an array with strong parameters
Ruby :: ハッシュを配列に変換する
[Ruby]配列をマージ・結合する
【Ruby入門】defについてまとめてみました(return,self,defined)

2
0
0

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
2
0