遠い世界の数式
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
よりは、とこの場合は。
追記
最初に書いた正規表現による回答をもう少しいじってみたのいくつかと、さすがにこればかりもなってことでいくらかはマシかなっていうのを一つ。
ちょいちょい忘れちゃうんだけど、正規表現を生成するのはそれなりに重い。
こうして見てみて意外だったのは、最初に書いたのがわりといい結果だったこと。send
をcase
にするともうちょっといけるかな。