fizzbuzz再考(no if, 遅延評価配列)

先端技術開発の三谷です。

fizz_buzz 問題に取り組む機会があり、”pythonで綺麗に書く”ために再考してみました。

ここでは、3の倍数で”fizz”, 5の倍数で”buzz”, 両方で”fizzbuzz”, それ以外が数値文字 という問題に取り組みます。

fizz_buzz問題で個人的に目指したいこととして、分岐を極力書かないことを念頭に置きました。
ここで、最終的な問題解決に直結するところですが、fizz_buzz問題の分岐を書かないことを助ける点として、
“fizzbuzz” は、”fizz”と”buzz”の文字列的足し算になっている点です。

そこで考えついた戦略は、与えられた数値が、
(3の倍数時は”fizz”, それ以外は””) + (5の倍数時は”buzz”, それ以外は””) + (前出の文字があれば””, なければ数値文字)
の3つの要素の足し算を施すという考え方です。

この足し算の中で表記上は分岐が現れます。これを分岐とさせないようにするため、pythonの文字列演算テクニックについて触れておきます。
否定演算を文字列に演算し、更に別の文字列の積を取ります。

(Python 3.6.4 で確認)

つまり、否定演算される文字列が空文字列ではない場合、後続の文字列演算積は空になり、逆の条件では積演算文字列がそのままに出力される となります。

これで、与えられた数値を fizz, buzz, fizzbuzz, 数値文字 とする際の条件分岐を無くせます。

次に、上記を実現する配列の用意となります。
ここで、遅延評価配列を作成できるcycle を利用します。
これは、例示がわかりやすいです。

と、与えられたリストの要素をnextを呼ぶたびに出力してくれる配列です。
この配列を、各倍数に合わせて作っていきます。
例えば3の倍数の時の”fizz” は、
cycle([“”, “”, “fizz”]) -> “”, “”, “fizz”, “”, “”, “fizz”….
となります。

前述の否定演算と文字列の積のテクニックを利用して作成した、if分岐を書かない、遅延評価配列を利用したfizzbuzz問題のコードの例は以下になります。