UKさんの404 NotFound|ステキなウエディングをうじひささんがnowa サービス終了のお知らせにて添削されていたので、便乗して僕も書いてみた。まだうじひささんのコードは読んでない。いま僕が持ってる知識(当然マニュアルは参照した)を使って僕ならどう書くかという現段階の僕の答えです。
まず、元のコード
class String def rpn @expr = self.split(" ") stack = Array.new @expr.each {|i| if i == "+" || i == "-" || i == "*" || i == "/" stack = calc(i, stack) else stack << i end } return stack[0] end private def calc(operator, stack) return Array(stack[1..-1].inject(stack[0].to_i){|result, i| reslut = result.__send__(operator, i.to_i) }) end end
テスト用コードは表示できるようにした以下のものを使います
require 'rpn.rb' p "2 8 +".rpn p "4 6 -".rpn p "81 9 /".rpn p "4 3 *".rpn p "3 7 + 10 20 + 2 * 10 + 80 -".rpn
そして、おいらのコード
class String # Reverse Polish Notation # '4 5 +'.rpn => 4 + 5 = 9 def rpn @stack = [] self.split(' ').each do |i| case i when /\d/ @stack.push(i.to_i) when %r|[-+*/]| @stack.push(i.calc(@stack.pop, @stack.pop)) if @stack.size >= 2 end end @stack.first end protected # Calculation Function # '+'.calc(4, 5) => 9 def calc(n, p) case self when '+' p + n when '-' p - n when '*' p * n when '/' p / n end end end
結果
% ruby rpn_test.rb 10 -2 9 12 10
おっけー。でも最後のは式自体が間違ってる(後述)
意識した点
- 文字列は式展開する時以外はシングルクォート
- 配列の宣言はなんらかの理由で意識的にする場合以外は[]
- 式の配列は別に作らずに、splitの戻り値をeachで直接回す
- 複数行に渡るブロックはdo-endではさむ
- if-elseじゃなくてcase-whenでまとめる
- 演算子をまとめたり、数字のみで指定したかったのでwhenの条件式を正規表現に
- スタックを意識する為にpush&popメソッド
- 配列の一番目へのアクセスはfirstメソッド
- returnは使わない
- calc内がややこしかったので単純に演算子を判別して計算するだけ(もっとスマートに書きたい><)
- 現在スタックされてる数はチェックしてるが、他の例外処理は今回は省略
- 演算子と数値の数の不一致とか、数字じゃなかったらどうするかとか、0の割り算とか・・・
- 最後の式は数の不一致で最初の3+7の答えが結果になってしまってる><
- もしかしてわざとなのでしょうか?
結論
もっと勉強してきます><
がんば、僕。
とりあえず今からうじひささんの回答を見る。しかし、正解というのはないと思うのであくまで参考ということで。
余談
うじひささんのことが大好きすぎて困ってます。研究室を特定して、院入試の概要見たりなんかしてませんよ。
追記
読んだ!土俵が違った!もっとがんばる><
テストコード書けるようにならなきゃだ。
さらに追記
あれ、逆ポーランド記法って2つ以上の組み合わせにも対応してるんですか?それなら計算合いますね。(というかinjectにしてるのがその処理ですね。)
むーほんとに土俵が違ったようだ。
出直そう。
今日の成果
class String # Reverse Polish Notation # '4 5 +'.rpn => 4 + 5 = 9 def rpn stack = [] opr = %q[ + - * / ] split(' ').each do |i| if opr.include? i stack[-1] = stack[-2].__send__(i, stack.pop) else stack << i.to_i end end stack.first end end
いろいろパクって、いろいろ自分のスタイルを曲げた><
まだスタイルが確定してないからいいの!
あと、逆ポーランド記法は間違ってないと仮定して、例外処理を一切排除。
注:調べてるけど、多分逆ポーランド記法は2つの数字の組に対して演算していくはず。