はてブロ@ama_ch

https://twitter.com/ama_ch

FizzBuzz問題が難しかった

codepad(http://codepad.org/)という素晴らしいサイトを昨日初めて知り、FizzBuzz問題でもやろうと思って書いてみました。

for n in range(1, 101):
    if n % 15 == 0:
        print "FizzBuzz"
    elif n % 3 == 0:
        print "Fizz"
    elif n % 5 == 0:
        print "Buzz"
    else:
        print n

なんかもっと、短く書けそうなんだけど、頭が回らない>< Python確か条件演算子とかないしなぁ・・・
とりあえずぐぐってみた。
FizzBuzz - Pythonのお勉強FizzBuzzがすげぇ!!

for i in range(100):print i%3/2*"Fizz"+i%5/4*"Buzz"or-~i

なんじゃこりゃ〜!


必死こいて理解した(つもり)ので、解説してみます。
・まず、i in range(100)で0〜99の値が生成される!
1〜100に対しての処理なのに、このプログラムは0〜99で動きます。
・i % 3 / 2 * "Fizz"
これは、「iの値を3で割った余りを2で割り、その数だけ"Fizz"と表示する」という意味です。意味わからん!具体的な数字で見てみます。
i = 2のときを考えます。0〜99なので、2は「3番目」の値です。3の倍数なので、Fizzと表示すれば良いですね。
2 % 3 これは2です
2 / 2 これは1です
従って、i = 2のとき、 i % 3 / 2 == 1 となり、1回Fizzと表示されます。すごい!
Buzzについても同じような感じです。これでFizzとBuzzの表示についてはわかりました。


・-~iってなんだ?
みんな大嫌いなビット演算ですね!これを書き換えると、
i = ~i
i *= -1
こんな感じの2ステップに分解できます。ひとつずつみていきましょう。
・i = ~i
~は「ビットを反転する」という意味です。iが3なら、iは「0011」→「1100」となります。
と、ここで2の補数表現についておさらいしておきます。「1100」は最上位ビットが1なので、マイナスの値です。ひとまずマイナスを外した値を知りたいので、ビットを反転して+1してみます。
1100→(ビット反転)→0011→(+1)→0100 = 4
1100は、-4であるとわかりました。
・i *= -1
符号の反転をします。つまり、先の処理を踏まえ、iが3のときは4と表示されます。


まとめると、0〜99の数に対して
・3で割った余りが2なら"Fizz"と表示
・5で割った余りが4なら"Buzz"と表示
・上のどちらにも当てはまらなければ、数を表示
という処理であると理解できました。0〜99なのに、-~iと書くことで、1加えた値を表示するなんて想像もつかなかった。こんなに凄いFizzBuzzもあるんですね!