質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Q&A

解決済

3回答

3984閲覧

RubyでYAMLから値を取り出す際、YAMLに値が追加されても変更が必要ないコードを作成したい

退会済みユーザー

退会済みユーザー

総合スコア0

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

0グッド

0クリップ

投稿2017/03/08 02:27

##伺いたいこと
作成したコードでは、下記YAMLにさらに深いrevelのコードが追加された場合、書き換える必要があります。
YAMLにさらに深いrevelのコードが追加されても書き換える必要がないコードの書き方を教えていただきたいです。

やりたいこと

下記のYAMLから値を取り出して出力するプログラムを作りたい。

lang

1revel1-1: foo 2revel1-2: 3 revel2-1: bar 4 revel2-2: 5 revel3: baz 6revel1-3: 7 revel2: 8 revel3: 9 revel4: qux

###期待する出力
revel1-1はfooです
revel1-2のrevel2-1はbarです
revel1-2のrevel2-2のrevel3はbazです
revel1-3のrevel2のrevel3のrevel4はquxです

##作成したコード
上記のYAMLから値を取り出すために下記のコードを作成しました.
###自分の考え

yamlを取り込むとhashとして取り扱うので、

  1. keyとvalueに分割する
  2. valueがhashかどうか調べる、
    • hashであれば1に戻る
    • hashでなければこれまでのkeyとvalueを出力する

lang

1require 'yaml' 2revel = YAML.load_file("revel.yml") 3revel.each do |a,b| 4 if b.instance_of?(Hash) 5 b.each do|c,d| 6 if d.instance_of?(Hash) 7 d.each do |e,f| 8 if f.instance_of?(Hash) 9 f.each do|g,h| 10 p "#{a}の#{c}の#{e}の#{g}は#{h}です" 11 end 12 else 13 p "#{a}の#{c}の#{e}は#{f}です" 14 end 15 end 16 else 17 p "#{a}の#{c}は#{d}です" 18 end 19 end 20 else 21 p "#{a}は#{b}です" 22 end 23end 24

上記ご指導のほどよろしくお願いいたします.

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

revel.yml

revel1-1: foo revel1-2: revel2-1: bar revel2-2: revel3: baz revel1-3: revel2: revel3: revel4: qux

a.rb

ruby

1require 'yaml' 2 3def print_revel(revel, parent = nil) 4 revel.each do |key, val| 5 label = parent.nil? ? "#{key}" : "#{parent}#{key}" 6 if val.is_a?(Hash) 7 print_revel(val, label) 8 else 9 puts "#{label}#{val}です。" 10 end 11 end 12end 13 14revel = YAML.load_file("revel.yml") 15print_revel(revel)

実行結果

$ ruby a.rb revel1-1はfooです。 revel1-2のrevel2-1はbarです。 revel1-2のrevel2-2のrevel3はbazです。 revel1-3のrevel2のrevel3のrevel4はquxです

投稿2017/03/08 14:43

katoy

総合スコア22324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/03/08 15:11

勉強になります。
退会済みユーザー

退会済みユーザー

2017/03/09 02:24

##回答 なるほど! rubyのメソッドの引数にはデフォルト値を設定できるんですね! また、プログラムを考える際には変化を管理したいものを変数に置くんですね。 今回の場合は、子レベルによって親レベルの長さが変わるので、親レベルの変化をlabel変数にして管理する。 ありがとうございます!とても勉強になりました!! >通常引数は呼び出し側とメソッド定義側で数が一致している必要がありますが、メソッド定義側では引数にデフォルト値を設定することが可能です。書式は次の通りです http://www.rubylife.jp/ini/method/index4.html 例えば ``` revel1-2"=>{"revel2-1"=>"bar", "revel2-2"=>{"revel3"=>"baz"}} ``` の処理 ```ruby key = revel1-2 val = {"revel2-1"=>"bar","revel2-2"=>{"revel3"=>"baz"}} parent = nil #parentがnilなので label = revel1-2 ``` valがハッシュなのでもう一度分割する ```ruby key = revel2-1 val = bar parent = revel1-2 #parentがnilでないので現在のkeyを繋げる lavel = revel1-2のrevel2-1 #valがハッシュではないので出力して次のkeyへ #=>revel1-2のrevel2-1はbarです。 ``` ```ruby key = revel2-2 val = {"revel3"=>"baz"} parent = revel1-2 #parentがnilでないので現在のkeyを繋げる lavel = revel1-2のrevel2-2 ``` valがハッシュでなのでもう一度分割 ```ruby key = revel3 val = baz parent = revel1-2のrevel2-2 #parentがnilでないので現在のkeyを繋げる label = revel1-2のrevel2-2のrevel3 #valがハッシュではないので出力 #=>revel1-2のrevel2-2のrevel3はbazです。 ```
guest

0

ベストアンサー

僕はrubyが苦手でして…生理的に受け付けない言語といいますか。 なので具体的なコードは書けませんが、デザインパターンからアドバイスだけします。

構造はComposite(コンポジット)パターンと言います。
簡単にいうと、コンポジットパターンとはディレクトリとファイルの構造のことです。

コンポジットパターンに適用できる各要素にアクセスするために使えるパターンが2つあります。

各要素にアクセスする手段を要素自身に任せるのがvisitor(ビジター)パターンです。
考え方としては、ルート要素にファンクタを渡します。
要素は自身にファンクタを適用し、自身の子供にファンクタをパスします。
子供は子供自身にファンクタを適用し、子供がいればその子供にファンクタをパスします。
この再帰構造を使えば全要素の値がファンクタに入る=参照できる、という寸法です。
そのためのメソッドを要素に共通で1つだけ持ちます。
Visitorパターンはちょっと分かりづらいですけどね…(良い説明サイトがないといつも感じる。)

Iteratorパターンにするという方法もあります。
Iteratorパターンは、自身の要素を並べるパターンのことです。
応用して、自分自身と、自分自身の子供を返すということを繰り返してネストされた構造を1層構造に見せることができれば全要素にアクセスできるようになります。

投稿2017/03/08 02:38

編集2017/03/08 02:49
haru666

総合スコア1591

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/03/08 02:50

早速の回答ありがとうございます! デザインパターンの勉強が足りないことがわかりました! 早速、コンポジットパターンを調べます! ありがとうございました!
guest

0

Ruby

1#encoding : utf-8 2data = open("yamlテスト.txt", &:read).chomp.split("\n").map{|e| e.split(":")} 3data.map!{|e| [e[0].count("\s"), e]} 4 5data.each_with_index do |element, i| 6 unless element[1][1].nil? 7 unless element[0].zero? 8 num = element[0] - 2 9 array = [] 10 loop{ 11 deco = data[i -= 1] 12 if deco[0] == num 13 array << deco[1][0] 14 num -= 2 15 if deco[0].zero? 16 break 17 end 18 end 19 } 20 array.reverse.each{|e| print e.strip + "の"} 21 end 22 puts "#{element[1][0].strip}#{element[1][1].strip}です" 23 end 24end

質問に書いてあったyaml?をメモ帳に書いて作ってみました。
スペースの増やし方を変更されると正常に動きません。

yamlテスト.txt

revel1-1: 100 revel1-2: revel2-1: 200 revel2-2: revel3: 212 revel1-3: revel2: revel3: revel4: 31 reverl5: 431 reverl6: 211 revel7: 543 revel1-4: 300 revel1-5: 327 revel2-1: 816 revel2-2: revel3: 938 revel1-6: revel2: revel3-1: revel4: 721 revel3-2: revel5-1: 642 revel1-7: revel2: 4 revel3: 87 revel4: reverl5: 966 reverl6: 71 revel7: revel8: 99 revel9: 901 revel10: 206 revel11: revel12: 12

実行結果例

revel1-1は100です revel1-2のrevel2-1は200です revel1-2のrevel2-2のrevel3は212です revel1-3のrevel2のrevel3のrevel4は31です revel1-3のrevel2のrevel3のrevel4のreverl5は431です revel1-3のrevel2のrevel3のrevel4のreverl5のreverl6は211です revel1-3のrevel2のrevel3のrevel4のreverl5のreverl6のrevel7は543です revel1-4は300です revel1-5は327です revel1-5のrevel2-1は816です revel1-5のrevel2-2のrevel3は938です revel1-6のrevel2のrevel3-1のrevel4は721です revel1-6のrevel2のrevel3-2のrevel5-1は642です revel1-7のrevel2は4です revel1-7のrevel2のrevel3は87です revel1-7のrevel2のrevel3のrevel4のreverl5は966です revel1-7のrevel2のrevel3のrevel4のreverl5のreverl6は71です revel1-7のrevel2のrevel3のrevel4のreverl5のreverl6のrevel7のrevel8は99です revel1-7のrevel2のrevel3のrevel4のreverl5のreverl6のrevel7のrevel8のrevel9は901です revel1-7のrevel2のrevel3のrevel4のreverl5のreverl6のrevel7のrevel8のrevel9のrevel10は206です revel1-7のrevel2のrevel3のrevel4のreverl5のreverl6のrevel7のrevel8のrevel9のrevel10のrevel11のrevel12は12です

私はyamlを詳しく知らないので、見当違いだったらすみません。

投稿2017/03/08 05:47

編集2017/03/08 13:12
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/03/08 09:03

回答ありがとうございます! スペースの数に注目するとこういう書き方ができるんですね! ちなみに YAMLとは構造化されたデータを表現するフォーマットのことです。 拡張子はymlです。 YAMLの書き方はこちらに詳しく記載されております。 http://magazine.rubyist.net/?0009-YAML rubyのyamlライブラリ https://docs.ruby-lang.org/ja/latest/library/yaml.html
退会済みユーザー

退会済みユーザー

2017/03/08 11:44

情報ありがとうございます。 面白そうですね(*'▽')
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問