プログラミングセンス

先日、うちの会社の入社試験(id:yaneurao:20050929)を公開し、たくさんの方の解答を見せてもらった。自分でも気づかなかったことが書かれていたりして大変興味深く拝見させていただいた。(まだチャレンジ中の人が居るので、解答はしばらく書かない。)


気になったのは、プログラミングセンスだ。「プログラミングの勉強」とは、「プログラミング言語を勉強すること」だと思われている節があるが、私に言わせればそんなのは瑣末な問題である。


たとえば、今回の問題、


ほげほげ(a(x,y-1)),
ほげほげ(a(x+1,y)),
ほげほげ(a(x-1,y)),
ほげほげ(a(x,y+1)),
のような式の順番で列挙している人が多い。本当はこの部分は、対称性を前面に打ち出して、

ほげほげ(a(x-1,y )),
ほげほげ(a(x+1,y )),
ほげほげ(a(x ,y-1)),
ほげほげ(a(x ,y+1)),
のように列挙すべきだ。ここでポイントとなるのは、


・どうやれば漏れがなく列挙できるか?
・2変数から3変数に拡張されたときにも同じやりかたで列挙できるか?
・4近傍から、8近傍や5×5近傍のように拡張されたときにも同じやりかたで列挙できるか?


である。前者の方法だと、a(x,y,z)のようになった場合、その6近傍( (x-1,y,z),(x+1,y,z),(x,y-1,z),(x,y+1,z),(x,y,z-1),(x,y,z+1) )を列挙するのにどういう順番になるのか想像もつかない。そう考えれば、a(x,y)のときだって、後者のような順番になっているほうが好ましいことに気づくはずだ。


他には


ほげほげ(a(x+1,y )),
ほげほげ(a(x-1,y )),
ほげほげ(a(x ,y+1)),
ほげほげ(a(x ,y-1)),
という順番が考えられるが、この場合、たとえば、(x,y)の3×3近傍を列挙するときに、このまま拡張したのでは、down countしている形になる。だから、数字は小さな値から列挙するのがセオリーだ。


もう一つのパターンは、


ほげほげ(a(x-1,y )),
ほげほげ(a(x ,y-1)),
ほげほげ(a(x+1,y )),
ほげほげ(a(x ,y+1)),
である。これは、-1するものを順番に列挙して、次に+1するものを順番に列挙するという考えかた。対称式を扱うときにこういう列挙の仕方をすることがあるが、この場合、(x,y)の周辺3×3を列挙するときにこのままでは拡張し辛い。


以上に見てきたように、列挙する順番ひとつにしてもセンスが問われる。しかも、残念ながら、こういったセンスはプログラミング言語の勉強をいくらやろうともおそらくは身にはつかない。また場合によっては誰かにレビューされない限り、一生かかっても気づかないだろう。


実際、こういう部分を意識していない人は、ケアレスミスが発生しやすい。人間である限り、ケアレスミスは避けて通れない問題なのだが、少なくとも減らす努力はすべきだ。どうやったら減るのか?それがこのような対称性を明確に意識すること、そして、問題を一般化して考えておくことである。