プログラミング/ruby/遠い世界の数学 の履歴(No.3)
更新概要†
http://qiita.com/cielavenir/items/cadbc5e24525b6a86cf8
こちらで紹介されていた、
http://nabetani.sakura.ne.jp/kanagawa.rb/evalex/
このお題について、単純に面白そうだったので趣旨もよく理解しないまま一人でやってみました。
どうやらこういうものがあったらしいです。> 神奈川Ruby会議
http://regional.rubykaigi.org/kana01/contents/02_pair_programing.html
仕様について†
本来の仕様は数式を表わす文字列を受け取って、答えを表わす「文字列」を返さなければならないのですが、以下の関数の戻り値は整数になっていて、仕様を満たしていません。
ですので、すべて最後に .to_s を追加しないといけません。どうもすみません。
1. 始めに思いついた普通の(?)やり方†
部分統治でしこしこ計算する。
& の初期値が -1 なので、32ビット(31ビット?)以上の数値が出てくると破綻しそう。
LANG:ruby def calc(expr) expr.split('*').inject(1) do |result, expr| result * expr.split('+').inject(0) do |result, expr| result + expr.split('&').inject(-1) do |result, expr| result & expr.split('|').inject(0) do |result, expr| result | expr.to_i end end end end end
1-1. 短くした†
LANG:ruby def calc(s,o='*+&|') s.split(o[0]).map{|s|o=='|'?s.to_i: calc(s,o[1,3])}.reduce(o[0]) end
素直さや実行効率を考えると、たぶんこれが一番おすすめ。
1-2. もう1文字†
LANG:ruby def calc(s,o='*+&|') o==''?s.to_i: s.split(o[0]).map{|s|calc(s,o[1,3])}.reduce(o[0]) end
恐らくゴルフじゃないので怒られそう・・・
2. 正規表現で手抜きをする†
括弧を挿入してあとは eval
LANG:ruby def calc(expr) eval expr.gsub(/[^()*]+/, '(\\0)') .gsub(/[^()*+]+/, '(\\0)') .gsub(/[^()*+&]+/,'(\\0)') end
2-1. 短くした†
LANG:ruby def calc(s) eval s.gsub(/[^*]+/){"(#{$&.gsub(/[^+]+/){"(#{$&.gsub(/[^&]+/,'(\\0)')})"}})"} end
むしろ上のやつのが短い。
もっと短くできるかしら?
2-2. ループにした†
LANG:ruby def calc(s) eval %w(& + *).inject(->(s){s}){|f,o| ->(s){s.gsub(/[^#{o}]+/){"(#{f.call $&})"}}}.call(s) end
長くなった orz
3. 逆に考える†
LANG:ruby def calc(expr) eval expr.gsub(/[|\d]+/,'(\\0)') .gsub(/[&|\d()]+/,'(\\0)') .gsub(/[+&|\d()]+/,'(\\0)') end
3-1. 短くする†
LANG:ruby def calc(s) 1.upto(3){|i|s.gsub!(/[#{'|&+'[0,i]}\d()]+/,'(\\0)')};eval s end
これはかなりすっきりかも。
3-2. 邪悪なゴルフ†
LANG:ruby def calc(s) '&+'.gsub(//){s.gsub!(/[|#{$`}\d()]+/,'(\\0)')};eval s end
短くは、なる。
2-3. この方針でいくなら†
逆じゃないほうが1文字短い
LANG:ruby def calc(s) '+&'.gsub(//){s.gsub!(/[^*#{$`}()]+/,'(\\0)')};eval s end
4. 括弧を演算子の両側に入れる案†
LANG:ruby def calc(s) eval "(((#{s.gsub(/[*]/, ')\\0(') .gsub(/[*+]/, ')\\0(') .gsub(/[*+&]/, ')\\0(')})))" end
あるいは、
LANG:ruby def calc(s) eval "(((#{s.gsub(/\*/, ')))*(((') .gsub(/\+/, '))+((' ) .gsub(/\&/, ')&(' )})))" end
4-1. ゴルフ†
LANG:ruby def calc(s) '+&'.gsub(//){s.gsub!(/[*#{$`}]/,')\\0(')};eval "(((#{s})))" end
最後に括弧で括るところで長くなる。
質問・コメント†
Counter: 5564 (from 2010/06/03),
today: 1,
yesterday: 0