[Python入門]FizzBuzz問題をPythonで遊ぼう。

FizzBuzz問題って?

FizzBuzz問題というのは、英語圏の言葉遊びを基にしたプログラミング初学者向けの問題です。
問題の概要は次の通りです。

  • 1から100までの数をカウントアップしながら表示する。
  • 数が3の倍数の時はFizzと表示する。
  • 数が5の倍数の時はBuzzと表示する。
  • 数が3の倍数かつ5の倍数(15の倍数)の時はFizzBuzzと表示する。

ルールはたったこれだけ。
単純な問題であるため学習用の例題や、初歩的な能力確認テストなどでしばしば用いられます。

実際にPythonで解いてみよう

いきなり解答の一つを貼ってしまうので、自力で取り組みたい方は各自エディタとにらめっこを始めてくださいね。

ベーシックな回答

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

特筆すべき点もない素直なコードです。
敢えて言うなれば問題文の順の通りに条件式を3の倍数、5の倍数、15の倍数の順で確認すると条件の優先順位が指定と合わないので気を付けなければなりません。
※実際には15は3と5のlcm(最小公倍数)で求めるべき数値ですが、多くの場合FizzBuzz問題では自明とされ特に算出式は記しません。

ベーシックな回答2

for i in range(1, 101):
    s = ""
    if i % 3 == 0:
        s = "Fizz"
    if i % 5 == 0:
        s += "Buzz"
    if s:
        print(s)
    else:
        print(i)

こちらも比較的ベーシックな回答。
Pythonは文字列の結合が+で済むのでこういったコードも書きやすいですね。

もう少し遊んでみよう

先述の通りこれは基礎の確認レベルの問題です。
せっかくなのでいろいろな書き方でPythonを楽しんでみましょう!

単なるカウントアップ部分をまとめる

fizz = 3
buzz = 5
n = 1
while n <= 100:
    x = min(fizz, buzz, 101)
    if n != x:
        print(*range(n, x), sep="\n")
        n = x
    else:
        s = ""
        if n == fizz:
            s = "Fizz"
            fizz += 3
        if n == buzz:
            s += "Buzz"
            buzz += 5
        n += 1
        print(s)

カウントアップしていく数の表示をrangeのアンパックで行っているコードです。
次にfizzあるいはbuzzとなる数値を管理して、whileを回しながらカウントアップを進めています。
最大でも2つしか数が連続することはないため、わざわざ…といった感じも否めません。

ジェネレータの利用

def my_generator(n, s):
    while True:
        for _ in range(n-1):
            yield ""
        yield s

fizz_gen = my_generator(3, "Fizz")
buzz_gen = my_generator(5, "Buzz")
for i in range(1, 101):
    fizz = next(fizz_gen)
    buzz = next(buzz_gen)
    if fizz or buzz:
        print(fizz, buzz, sep="")
    else:
        print(i)

剰余算で行っていた約数の処理をジェネレータのループで代替したコードです。
“FizzBuzz”を表示するためにsepを空文字にするのを忘れずに。

最大公約数と辞書

import math
dic = {3: "Fizz", 5: "Buzz", 15:"FizzBuzz"}
for i in range(1, 101):
    print(dic.get(math.gcd(i, 15), i))

約数の処理を最小公倍数の算出によって行うテクニカルなコードです。
3の倍数でも5の倍数でもない数をgetメソッドのデフォルト値として取得できるのがかっこいいですね!

numpy配列

import numpy as np
ar = np.arange(1, 101)
fizz_idx_bool = ar % 3 == 0
buzz_idx_bool = ar % 5 == 0
ar = ar.astype(str)
ar[fizz_idx_bool] = "Fizz"
ar[buzz_idx_bool] = "Buzz"
ar[np.logical_and(fizz_idx_bool, buzz_idx_bool)] = "FizzBuzz"
print(*ar, sep="\n")

numpyのブールインデックス参照を用いてFizzBuzz出力配列を生成するコードです。
ブロードキャストを用いた剰余算によって真偽型配列を生成して、”Fizz”, “Buzz”, “FizzBuzz”に値を置換していきます。
numpy配列のデータ型を保つため、ブールインデックス用の配列生成後、元配列は文字列型に変更する必要があるのに注意です。


Pythonicであるとか、可読性が高いとか、速度が速いだとかコードの最適化に気を払うのは疲れてしまいます。
たまにはプログラミング言語を遊び道具にしてしまうのも、頭の体操にいいですね。

>Python TIPSのほかの記事を読む
>開発者ブログのほかの記事を読む

ライター:H.I