FizzBuzzのしくみ
id:yoosaki:20070510#p1
いくら見ても意味がわからないので、irbで動かしてみた。
(コーディング環境はeclipseに移したけれど、こういうときに役に立つからEmacsが捨てられない)
肝はここ。
s=[[:Fizz][i%3],[:Buzz][i%5]]*''
:Fizz は 'Fizz' をシンボルで書いて一文字短縮したとわかる*1。
わからんのが[:Fizz][i%3]と、最後の*''。
調べてみたら、RubyではArrayに文字列をかけるとArray#joinと同じ効果があるとわかった。
[1,2,3].join(';') = "1;2;3"
すなわち
[1,2,3]*';' = "1;2;3"
というわけ。
さて問題は[:Fizz][i%3]ですよ。
「配列と配列を並べて書くとどう動作する?」とか悩んでしまいましたがまったくの無駄で、[i%3]は[:Fizz]に対する添字です。
i%3はiのあまりなので、iが1,2,3,4,5,6,……と変化すると、i%3は1,2,0,1,2,0,……となる。
すなわち
[:Fizz][0] = :Fizz [:Fizz][1] = nil [:Fizz][2] = nil
というわけで、この式はiが3で割り切れるときのみ:Fizzを返すわけです。
Buzzについても同様で、肝の式の前半は
[nil, nil] [:Fizz, nil] [nil, :Buzz] [:Fizz, :Buzz]
の4つの値をとりうることになる。
これを''でjoinするから、sの値は'', 'Fizz', 'Buzz', 'FizzBuzz'のいずれか。
てことはs[1]はnilか?iか?uになる。s[1]がnilのときだけiを返すため、最後はs[1]?s:iとなる寸法です。(s[0]を見ても可っぽい)
こういう遊びをコードゴルフというそうです。
プログラムの文字数を打数に見立て、文法知識と発想力を駆使して一文字でも短く書いて行くわけです。
ちなみにこれより短い56バイトの例がすでにここに。
id:yoosaki:20070516#p1
これはこれでまた読み込まないと意味がわからない!!