会話をしていると、FizzBuzzの話になった。何かの拍子にFizzBuzzを書いてくださいと言われたらどうするだろうか、と思ってちょっと書いてみることにした。たまには気楽に書けるものもよい。
FizzBuzzを自然に捉えると、数字を文字列に変換していくルールに従って、入ってくる数字の列を変換し順に出力するというものだろう。
ということは、iota
的なイテレータをtransform_iterator
で覆って、ostream_iterator
に投げ込んでいけばいい。
iota
的なことをしてくれるイテレータはないかと探したところ(作れるが演算子定義などが面倒だ)、boost::iterator::counting_iterator
がよいとわかった。
#include <boost/iterator/transform_iterator.hpp> #include <boost/iterator/counting_iterator.hpp> #include <algorithm> #include <iostream> #include <string> int main(int argc, char** argv) { if(argc != 2) { std::cerr << "usage: ./fizzbuzz <maximum>" << std::endl; return 1; } const auto fizzbuzz = [](const std::uint64_t i){ using namespace std::literals::string_literals; if(i%3 == 0 && i%5 == 0) return "FizzBuzz"s; else if(i%3 == 0) return "Fizz"s; else if(i%5 == 0) return "Buzz"s; else return std::to_string(i); }; std::copy( boost::make_transform_iterator( boost::make_counting_iterator(1ull), fizzbuzz), boost::make_transform_iterator( boost::make_counting_iterator( std::stoull(argv[1]) + 1ull), fizzbuzz), std::ostream_iterator<std::string>(std::cout, ", ")); std::cout << std::endl; return 0; }
こんなもんだろう。しかしまあ、1からmaxまでの数字の列を作って、それに関数を適用するだけだというのに非常に面倒なことをしないといけないのはやはり辛い。これくらい簡単になってもよいと思うのだが。
#include <algorithm> #include <iostream> #include <string> int main(int argc, char** argv) { if(argc != 2) { std::cerr << "usage: ./fizzbuzz <maximum>" << std::endl; return 1; } const auto fizzbuzz = [](const std::uint64_t i){ if(i%3 == 0 && i%5 == 0) return "FizzBuzz"s; else if(i%3 == 0) return "Fizz"s; else if(i%5 == 0) return "Buzz"s; else return std::to_string(i); }; const auto max = std::stoull(argv[1]); (1ull ... max).transform(fizzbuzz).output(std::cout, ", "); return 0; }
と、思った辺りでBoost.rangeの存在を思い出した。
#include <boost/range/algorithm.hpp> #include <boost/range/irange.hpp> #include <boost/range/adaptor/transformed.hpp> #include <iostream> #include <cstdint> int main(int argc, char** argv) { if(argc != 2) { std::cerr << "usage: ./fizzbuzz <maximum>" << std::endl; return 1; } const auto fizzbuzz = [](const std::uint64_t i){ using namespace std::literals::string_literals; if(i%3 == 0 && i%5 == 0) return "FizzBuzz"s; else if(i%3 == 0) return "Fizz"s; else if(i%5 == 0) return "Buzz"s; else return std::to_string(i); }; boost::copy(boost::irange(1ull, std::stoull(argv[1]) + 1ull) | boost::adaptors::transformed(fizzbuzz), std::ostream_iterator<std::string>(std::cout, ", ")); std::cout << std::endl; return 0; }
やはりこうするとかなりマシだ。