漫画『酒男子』のAIボットを作ると高級日本酒が当たる!! >>

『初めてのプログラミング』を読んでRubyを勉強しています。その中にある問題でp.127の『ローマ数字をアラビア数字に変換するプログラム』を書け、というのがありまして、最初に入力したローマ数字を弾く部分を書いているのですが…(以下コード)
puts 'Enter roman numeral.'
roman = gets.chomp.upcase
roman_array = roman.to_a

def char_checker(char)
parts = ['I', 'V', 'X', 'L', 'C', 'D', 'M']
parts.each do |part|
if part != char
char = false
elsif part == char
char = true
return char
end
end

puts char_checker('X')

(以上コード)
このchar_checker, なぜかpartsを返してきます。返してほしいのはcharのtrueかfalseなのに泣 書いたコードに間違いがあるのはわかっているのですが、どこで間違っているのかがどうしてもわかりません。わかる方回答よろしくお願いします。ちなみに環境はMac OS X 10.5.4でrubyのバージョンはバンドルされている1.8.6です。

このQ&Aに関連する最新のQ&A

A 回答 (4件)

>変数の使い回しとは配列のpartsと|part|のことでしょうか。


いえ、ちがいます。

def char_checker(char) ← のchar と

char = false
char = true

で使っている char のことです。

> イテレータ部分の最初でcharがfalseに変えられてしまうの で、elsif part == charに引っかからなくなってました。

はい。そういうことです。
> 最後に評価された文だから'M'だけ出力されるはずなのに…
いいところをついていますが、ちょっと違います。
確かにメソッドに return がない場合には最後に実行された文(式)の値が
メソッドの返す値になるというのはそのとおりなんですが、
「最後に実行されたものは何か」ということです。
実はrubyでは、if 文なども値を返します。そして今回のように
[配列].each do ... end も同じなんです。
irb というコマンドを使うと対話的にRubyが実行できるので試してみてもらいたいのですが、

irb(main):009:0> ['h', 'e', 'l', 'l', 'o'].each {|e| e[0]}
=> ["h", "e", "l", "l", "o"]
irb(main):010:0> ['h', 'e', 'l', 'l', 'o'].each {|e| puts e[0]}
104
101
108
108
111
=> ["h", "e", "l", "l", "o"]
irb(main):011:0>
この、=> の後に書かれているのがこの each を含んだ文の「値」です。
ということは、
def char_checker(char) このメソッドの「最後の文」は
each do end の中にある文ではなくて、each している文そのものなんです。
ということで配列の中身であるI V X L C D M が全部出てきているというわけです。
そしてもうひとつ
irb(main):001:0> def hoge
irb(main):002:1> puts "hoge が呼ばれました"
irb(main):003:1> "hello!"
irb(main):004:1> end
=> nil
irb(main):005:0> hoge
hoge が呼ばれました ← メソッドの中の puts で出力されたもの
=> "hello!"
irb(main):006:0> puts hoge
hoge が呼ばれました ← メソッドの中の putsで出力されたもの
hello! ← メソッド hogeの戻り値を puts した結果
=> nil ← puts hoge の「値」

puts という「文の値」が nil なので
> def文の最後にputs 'Lucky Stirike'と入れるとpartsの中身は出力されなくなりLucky Strikeと出力されました。
となるわけです。

こんなんで納得できますか?
    • good
    • 0
この回答へのお礼

すっきりしました。irbすごい便利ですね!ありがとうございます。これからirbを駆使してこのプログラムを完成させたいと思います。またお世話になるかもしれませんが、その時はよろしくお願いします(^_^;)

お礼日時:2008/08/18 01:43

> どこで間違っているのかがどうしてもわかりません。



実行時のエラーメッセージの全文を正確に提示してください。
ところで、

> roman = gets.chomp.upcase
> roman_array = roman.to_a

この部分の意図は、どういったものでしょうか。

> puts char_checker('X')

ここで'X'固定にしている訳も教えてほしいです。
    • good
    • 0
この回答へのお礼

>実行時のエラーメッセージの全文を正確に提示してください。
えーと、エラーではなくてちゃんと実行されるのですが思った通りに動いてくれなかったんです。

>この部分の意図は、どういったものでしょうか。
これは実験で、Xだとどう動いてくれるかな~と思ってしました。

他の方の回答で解決しましたが、丁寧に回答していただきありがとうございます!!

お礼日時:2008/08/18 01:51

変数の使い回しは止めましょう。


メモリを節約しているつもりかもしれませんが、意味ありません。

で、char_checker に一行書き加えて、何がどうなっているのかよく考えてみてください。

def char_checker(char)
parts = ['I', 'V', 'X', 'L', 'C', 'D', 'M']
parts.each do |part|
puts "char=#{char}, part=#{part}" #追加
if part != char
char = false
elsif part == char
char = true
return char
end
end
end

この回答への補足

アドバイスありがとうございます!!変数の使い回しとは配列のpartsと|part|のことでしょうか。メモリの節約とかそんな高度なことは考えてなかったんですが…
追加部分を加えて再度実行してみたところ、
bash-3.2$ ruby roman_arabian_again.rb
char=X, part=I
char=false, part=V
char=false, part=X
char=false, part=L
char=false, part=C
char=false, part=D
char=false, part=M
I
V
X
L
C
D
M
と出ました。イテレータ部分の最初でcharがfalseに変えられてしまうので、elsif part == charに引っかからなくなってました。
puts "char=#{char}, part=#{part}"←こんなチェックの仕方があるとは知りませんでした。勉強になります!
それで、配列"parts"の中身が出力されている件なんですが、試しにdef文の最後にputs 'Lucky Stirike'と入れるとpartsの中身は出力されなくなりLucky Strikeと出力されました。おそらくputs char_checker('X')で、char_checkerが"最後に"評価した文(この場合はif part != char)をputsに渡してるんだろうと思います。しかしそうだとすると最後に評価された文だから'M'だけ出力されるはずなのに… おこがましいですが何かお答えいただけたらと思います。

補足日時:2008/08/16 14:24
    • good
    • 0

このプログラムだとifに対応するendが無くてエラーになりますけど。

    • good
    • 0
この回答へのお礼

ご指摘ありがとうございます。プログラム自身はちゃんと書いてあるんですが手打ちで書いたんでendが一つ抜けてしまいました。これからはコピペするようにします。

お礼日時:2008/08/17 01:57

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!


人気Q&Aランキング