遠い世界の数式

Kanagawa.rb#01に参加した。

ペアプロ問題「遠い世界の数式」私の回答

会場で書いた回答。

s = eq.dup # 計算式

%w(| & + *).each do |op|
  r = /(\d+)#{Regexp.quote(op)}(\d+)/
  true while s.sub!(r) do
    $1.to_i.send(op, $2.to_i)
  end
end

puts "#{eq} #=> #{s} (#{s == a})" # sが計算結果、aは正解
raise unless s == a

うーん、true while ...がなあ。

上の改良?

帰宅後、なんとなく納得いかなくて考えたえーいevalだ版。

s = eq.dup # 計算式

%w(| & + *).each do |op|
  s.gsub!(/\d+(?:#{Regexp.quote(op)}\d+)+/) { eval $& }
end

puts "#{eq} #=> #{s} (#{s == a})" # sが計算結果、aは正解
raise unless s == a

んー、evalなあ……。

ていうか合ってるかな?

やっぱevalやめた

s = eq.dup # 計算式

%w(| & + *).each do |op|
  s.gsub!(/\d+(?:#{Regexp.quote(op)}\d+)+/) { $&.scan(/\d+/).map(&:to_i).reduce(op) }
end

puts "#{eq} #=> #{s} (#{s == a})" # sが計算結果、aは正解
raise unless s == a

このやり方で速度をうんぬんはアレですが、evalと比べてどうかって意味でお題の計算を100回繰り返した結果を参考までに:

Rehearsal -----------------------------------------
eval:   0.670000   0.000000   0.670000 (  0.678982)
call:   0.610000   0.000000   0.610000 (  0.608114)
-------------------------------- total: 1.280000sec

            user     system      total        real
eval:   0.670000   0.010000   0.680000 (  0.670568)
call:   0.610000   0.000000   0.610000 (  0.610448)

まあ、わりとガチャガチャやってもevalよりは、とこの場合は。

追記

最初に書いた正規表現による回答をもう少しいじってみたのいくつかと、さすがにこればかりもなってことでいくらかはマシかなっていうのを一つ。

kana01.rb

ちょいちょい忘れちゃうんだけど、正規表現を生成するのはそれなりに重い。

こうして見てみて意外だったのは、最初に書いたのがわりといい結果だったこと。sendcaseにするともうちょっといけるかな。