VC#でFizzBuzz

Contents:

for文を使った例

まずはもっともシンプルな例

 1using System;
 2using System.Linq;
 3
 4class Program
 5{
 6    static void Main(string[] args)
 7    {
 8        for (var i = 0; i < 101; i++)
 9        {
10            if (i % 3 == 0) Console.WriteLine("Fizz");
11            else if (i % 5 == 0) Console.WriteLine("Buzz");
12            else if (i % 15 == 0) Console.WriteLine("FizzBuzz");
13            else Console.WriteLine(i.ToString());
14        }
15    }
16}

ジェネレータを使った例

yield return():

を使う。

 1using System;
 2using System.Linq;
 3using System.Collections.Generic;
 4
 5class Program
 6{
 7    private static IEnumerable<string> fb(int m)
 8    {
 9        for (int i = 0; i <= m; i++)
10        {
11            if (i % 3 == 0) yield return ("Fizz");
12            else if (i % 5 == 0) yield return ("Buzz");
13            else if (i % 15 == 0) yield return ("FizzBuzz");
14            else yield return (i.ToString());
15        }
16        }
17    static void Main(string[] args)
18    {
19        foreach (var n in fb(100))
20        {
21            Console.WriteLine(n);
22        }
23    }
24}

Pythonの内包リストっぽく書く

かなり難しい。以下の理由であり、それぞれの解法を述べる。

  • 標準ライブラリでは文字列の繰り返しができない

  • 単一文字に変換し、最後にstring.replace()する

  • 文字列のor(=空白のときの代理文字列)がつかえない

  • 三項演算子で条件分岐する。

 1using System;
 2using System.Linq;
 3using System.Collections.Generic;
 4
 5class Program
 6{
 7    static void Main(string[] args)
 8    {
 9        for(int i =0; i <= 100; i++)
10        {
11            Console.WriteLine((new string('F', i % 3 == 0 ? 1 : 0) + new string('B', i % 5 == 0 ? 1 : 0)).Replace("F", "Fizz").Replace("B", "Buzz") + 
12                               new string('N', ( (i % 5) * (i % 3) ) != 0 ? 1 : 0).Replace("N",i.ToString()));
13        }
14    }
15}

三項演算子を使った例

そもそも三項演算子を使うなら、以下の例で良い。。。

 1using System;
 2using System.Collections.Generic;
 3
 4
 5class Program
 6{
 7    delegate bool cond(int i);
 8    delegate void proc(int i);
 9
10    static void Main(string[] args)
11    {
12        for (int i = 0; i <= 100; i++) Console.WriteLine(i % 15 == 0 ? "FizzBuzz" : i % 3 == 0 ? "Fizz" : i % 5 == 0 ? "Buzz" : i.ToString());
13    }
14}

KeyValuePairを使って条件分岐

fizzbuzzでgoogleしたところ、以下のような例を見つけた。

 1// 参考: http://blogs.wankuma.com/episteme/archive/2007/11/08/106821.aspx
 2using System;
 3using System.Collections.Generic;
 4
 5
 6class Program
 7{
 8    delegate bool cond(int i);
 9    delegate void proc(int i);
10
11    static void Main(string[] args)
12    {
13        KeyValuePair<cond, proc>[] fb =
14        {
15            /*
16             * 以下のように書いてもいいらしい
17            new KeyValuePair<cond ,proc>(
18            delegate(int c) { return c % 3 != 0 && c % 5 != 0; },
19            delegate(int c) { Console.Write(c); }
20            ),
21            */
22            new KeyValuePair<cond ,proc>(
23                (c => c % 3 != 0 && c % 5 != 0),
24                (c => Console.Write(c) )
25               ),
26            new KeyValuePair<cond,proc>(
27                (c => c % 3 == 0 ),
28                (c => Console.Write("Fizz") )
29                ),
30            new KeyValuePair<cond,proc>(
31                (c => c % 5 == 0 ),
32                (c => Console.Write("Buzz") )
33                ),
34        };
35
36        for (int i = 1; i <= 100; ++i)
37        {
38            foreach (KeyValuePair<cond, proc> kv in fb)
39                if (kv.Key(i)) kv.Value(i); Console.WriteLine("");
40        }
41    }
42}

てっきり、proc(int)はラムダ式でしか書けないと思っていたのだが、 参照したページによれば delegate(int c) という書き方ができるのですね。 delegate表記で引数のcに対する型を明記するという意味で、 delegateの方が読みやすいかもしれませんね。

Reactive Extensions

VisualStudio2012使っているのだからRxを使いましょう。ということで以下の例。

 1using System;
 2using System.Linq;
 3using System.Collections.Generic;
 4using System.Reactive;
 5using System.Reactive.Linq;
 6
 7
 8class Program
 9{
10    static void Main(string[] args)
11    {
12        var fb = Observable.Range(1, 100).Publish();
13        fb.Where(c => c % 3 == 0).Subscribe(c => Console.WriteLine("Fizz"));
14        fb.Where(c => c % 5 == 0).Subscribe(c => Console.WriteLine("Buzz"));
15        fb.Where(c => c % 3 != 0 && c % 5 != 0).Subscribe(c => Console.WriteLine(c.ToString()));
16        fb.Connect();
17    }
18}

Observable.Publish() は Connect() するまで列挙を始めないためのおまじないで、 これによって、条件分岐を定義してから列挙することが可能。 ちなみに、IEnumerableなオブジェクトは ToObservable() で 列挙オブジェクトに変換できるので、

 1using System;
 2using System.Linq;
 3using System.Collections.Generic;
 4using System.Reactive;
 5using System.Reactive.Linq;
 6
 7
 8class Program
 9{
10    public static IEnumerable<int> fblist(int m)
11    {
12        for (int i = 1; i <= m; i++) yield return i;
13    }
14    static void Main(string[] args)
15    {
16        var fb = fblist(100).ToObservable().Publish();
17        fb.Where(c => c % 3 == 0).Subscribe(c => Console.WriteLine("Fizz"));
18        fb.Where(c => c % 5 == 0).Subscribe(c => Console.WriteLine("Buzz"));
19        fb.Where(c => c % 3 != 0 && c % 5 != 0).Subscribe(c => Console.WriteLine(c.ToString()));
20        fb.Connect();
21    }
22}

とすることも可能。