FizzBuzzの最短コードの解析
前の記事でFizzBuzzの最短コードを紹介しました。
一見よくわからない変態コードですが、詳しく見るとそんなに難しい訳じゃなかったです。
問題のソースコード
http://d.hatena.ne.jp/y_tag/20110125/fizzbuzz
100.times{println'Fizz'*(it%3/2)+'Buzz'*(it%5/4)?:++it}
実行結果
1 2 Fizz 4 Buzz Fizz ... 中略... 98 Fizz Buzz
このままだとにくいので、変数作って三項演算子を普通のfor文にして、インデントしてから解析します。
100.times { def str = 'Fizz'*(it%3/2)+'Buzz'*(it%5/4) if (str) { println str } else { println (++it) } }
1行目
「100.times」
0〜99を順に、後のクロージャーに渡す。
(実行結果は1から100までの結果が出力されている事に注意。)
2行目
長いので少しづつ。
「'Fizz'*(it%3/2)」
「*」は文字列の繰り返しなので、「it%3/2」の数だけ繰り返す。
「it%3」は余りなので今回の場合
「0%3/2, 1%3/2, ... 99%3/2, 100%3/2」 → 「0, 0.5, 1」の繰り返し → 「"","","Fizz"」の繰り返し
同様に、Buzzの方は
「0, 0.25, 0.5, 0.75, 1」 → 「"","","","","Buzz"」の繰り返し
ということで、2つを「+」で繋げると
「"","","Fizz","","Buzz"...」となる。
表にしてみるとこんな感じ。
値 | 文字列 |
---|---|
0 | "" |
1 | "" |
2 | "Fizz" |
3 | "" |
4 | "Buzz" |
5 | "Fizz" |
3行目
「if (str)」
Groovyではifに文字列を渡すと空文字やnullの場合はfalseそれ以外はtrueを返す。
4行目
「println str」
という事なので、文字列がある場合はその文字列を表示
6行目
「println (++it)」
空文字の場合は渡された値に1をプラスして表示。
こんな感じみたいです。
1〜100を表示したいのに0〜99で処理を行っているのがポイント!
余りが0の時に表示するのではなく、余りが最大の時に表示するとかテクニックですねぇ。。。
ちなみに上記のGroovy最短コードは55バイトなんですが、rubyだと最短は56バイトらしいです。
なんかちょっと嬉しいのは私だけですか?
http://d.hatena.ne.jp/shinichiro_h/20070509#1178693484
他にも色々見つけたのでGroovy風にして書いてみました。
正規表現版
http://jarp.does.notwork.org/diary/200705b.html#200705111
f={n,i,s->"#"*n=~/^(${"#"*i})+$/?s:""} (1..100).each{println((s=f(it,3,"fizz")+f(it,5,"buzz"))?s:it)}
そんなこんなで、色々見た結果自力で頑張ってここまで縮めてみた。
わかりやすい、理解しやすいところだとこれが限界かな??><
(1..100).each{println((s=(it%3==0?"fizz":"")+(it%5==0?"buzz":""))?s:it)}
ちなみに、prinalnが冗長に感じたので削ってみたら長くなっちゃいましたw
(1..100).collect{((s=(it%3==0?"fizz":"")+(it%5==0?"buzz":""))?s:it)}.join("\n")