問題5のelixir版をruby版に翻訳してみた。
http://d.hatena.ne.jp/take_tk/20150710 で作った。
http://www.softantenna.com/wp/software/5-programming-problems/
1時間以内に解けなければプログラマ失格となってしまう5つの問題が話題に
の
問題5
1,2,…,9の数をこの順序で、”+”、”-“、またはななにもせず結果が100となるあらゆる組合せを出力するプログラムを記述せよ。例えば、1 + 2 + 34 - 5 + 67 - 8 + 9 = 100となる
のelixir版をrubyに翻訳してみる。
# prefix は文字列、rest は文字の配列 # 文字列の配列を返す。 # def make(prefix,rest=nil) # make/1 return make("", prefix.split(//)) if rest.nil? # make/2 h = rest[0] t = rest[1..-1] case when prefix == "" # 始め return make( h , t ) when rest == [] # 最後 if eval(prefix) == 100 return [ prefix ] else return [] end else # 途中 return make( prefix + '+' + h , t ) + make( prefix + '-' + h , t ) + make( prefix + h , t ) end # case end p( make '123456789' ) #=> ["1+2+3-4+5+6+78+9", "1+2+34-5+67-8+9", "1+23-4+5+6+78-9", "1+23-4+56+7+8+9", "12+3+4+5-6-7+89", "12+3-4+5+67+8+9", "12-3-4+5-6+7+89", "123+4-5+67-89", "123+45-67+8-9", "123-4-5-6-7+8-9", "123-45-67+89"]
確かに、rubyでも実行可能だ。elixirと同様にコンパクトだ。しかし…。
不安感が爆発するね。「これでよい」という安心感が全くない。
というより、何をやっているのかも理解不能だ。
そもそも、ruby脳で、これを作れと言われても作れないだろう。
何故混乱するかというと、
まったく異なった処理を行なうメソッドが、同じメソッドの中に入っている、というのが理解不能/不安の原因だな。
elixirの場合には引数のパターンごとに別の関数になっているので、その関数が呼ばれる場合だけを想定して理解すればよい。
ということで、ruby版で場合分けを行なうメソッドを分離してみた。elixir版とそっくりになった。
# prefix は文字列、rest は文字の配列 # 文字列の配列を返す。 # def make(prefix,rest=nil) # make/1 return make_1(prefix) if rest.nil? # make/2 h = rest[0] t = rest[1..-1] case when prefix == "" # 始め return make_first(prefix,h,t) when rest == [] # 最後 return make_last(prefix,rest) else # 途中 return make_mid(prefix,h,t) end # case end def make_1(prefix) make("", prefix.split(//)) end def make_first(prefix,h,t) # when prefix == "" make( h , t ) end # ↑ ruby版 ⇔ elixir版 ↓ # def make([],[h|t]) do # 始め # make( [h] , t ) # end def make_last(prefix,rest) # when rest == [] case eval(prefix) when 100 ; [ prefix ] else ; [] end end # ↑ ruby版 ⇔ elixir版 ↓ # def make(prefix,[]) do # 最後 # case Code.eval_string(prefix) do # {100, _} -> [ prefix ] # _ -> [ ] # end # end def make_mid(prefix,h,t) # else make( prefix + '+' + h , t ) + make( prefix + '-' + h , t ) + make( prefix + h , t ) end # ↑ ruby版 ⇔ elixir版 ↓ # def make(prefix,[h|t]) do # 途中 # make( prefix ++ '+' ++ [h] , t ) ++ # make( prefix ++ '-' ++ [h] , t ) ++ # make( prefix ++ [h] , t ) # end p( make '123456789' ) #=> ["1+2+3-4+5+6+78+9", "1+2+34-5+67-8+9", "1+23-4+5+6+78-9", "1+23-4+56+7+8+9", "12+3+4+5-6-7+89", "12+3-4+5+67+8+9", "12-3-4+5-6+7+89", "123+4-5+67-89", "123+45-67+8-9", "123-4-5-6-7+8-9", "123-45-67+89"]
このパターンで分解すると、問題が簡単になる、というケースは多いのだろうか?