VC#でFizzBuzz

Contents:

for文を使った例

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
using System;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        for (var i = 0; i < 101; i++)
        {
            if (i % 3 == 0) Console.WriteLine("Fizz");
            else if (i % 5 == 0) Console.WriteLine("Buzz");
            else if (i % 15 == 0) Console.WriteLine("FizzBuzz");
            else Console.WriteLine(i.ToString());
        }
    }
}

ジェネレータを使った例

yield return():を使う。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;
using System.Linq;
using System.Collections.Generic;

class Program
{
    private static IEnumerable<string> fb(int m)
    {
        for (int i = 0; i <= m; i++)
        {
            if (i % 3 == 0) yield return ("Fizz");
            else if (i % 5 == 0) yield return ("Buzz");
            else if (i % 15 == 0) yield return ("FizzBuzz");
            else yield return (i.ToString());
        }
        }
    static void Main(string[] args)
    {
        foreach (var n in fb(100))
        {
            Console.WriteLine(n);
        }
    }
}

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

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

  • 標準ライブラリでは文字列の繰り返しができない
  • 単一文字に変換し、最後にstring.replace()する
  • 文字列のor(=空白のときの代理文字列)がつかえない
  • 三項演算子で条件分岐する。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
using System;
using System.Linq;
using System.Collections.Generic;

class Program
{
    static void Main(string[] args)
    {
        for(int i =0; i <= 100; i++)
        {
            Console.WriteLine((new string('F', i % 3 == 0 ? 1 : 0) + new string('B', i % 5 == 0 ? 1 : 0)).Replace("F", "Fizz").Replace("B", "Buzz") + 
                               new string('N', ( (i % 5) * (i % 3) ) != 0 ? 1 : 0).Replace("N",i.ToString()));
        }
    }
}

三項演算子を使った例

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
using System;
using System.Collections.Generic;


class Program
{
    delegate bool cond(int i);
    delegate void proc(int i);

    static void Main(string[] args)
    {
        for (int i = 0; i <= 100; i++) Console.WriteLine(i % 15 == 0 ? "FizzBuzz" : i % 3 == 0 ? "Fizz" : i % 5 == 0 ? "Buzz" : i.ToString());
    }
}

KeyValuePairを使って条件分岐

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// 参考: http://blogs.wankuma.com/episteme/archive/2007/11/08/106821.aspx
using System;
using System.Collections.Generic;


class Program
{
    delegate bool cond(int i);
    delegate void proc(int i);

    static void Main(string[] args)
    {
        KeyValuePair<cond, proc>[] fb =
        {
            /*
             * 以下のように書いてもいいらしい
            new KeyValuePair<cond ,proc>(
            delegate(int c) { return c % 3 != 0 && c % 5 != 0; },
            delegate(int c) { Console.Write(c); }
            ),
            */
            new KeyValuePair<cond ,proc>(
                (c => c % 3 != 0 && c % 5 != 0),
                (c => Console.Write(c) )
               ),
            new KeyValuePair<cond,proc>(
                (c => c % 3 == 0 ),
                (c => Console.Write("Fizz") )
                ),
            new KeyValuePair<cond,proc>(
                (c => c % 5 == 0 ),
                (c => Console.Write("Buzz") )
                ),
        };

        for (int i = 1; i <= 100; ++i)
        {
            foreach (KeyValuePair<cond, proc> kv in fb)
                if (kv.Key(i)) kv.Value(i); Console.WriteLine("");
        }
    }
}

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

Reactive Extensions

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
using System;
using System.Linq;
using System.Collections.Generic;
using System.Reactive;
using System.Reactive.Linq;


class Program
{
    static void Main(string[] args)
    {
        var fb = Observable.Range(1, 100).Publish();
        fb.Where(c => c % 3 == 0).Subscribe(c => Console.WriteLine("Fizz"));
        fb.Where(c => c % 5 == 0).Subscribe(c => Console.WriteLine("Buzz"));
        fb.Where(c => c % 3 != 0 && c % 5 != 0).Subscribe(c => Console.WriteLine(c.ToString()));
        fb.Connect();
    }
}

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
using System.Linq;
using System.Collections.Generic;
using System.Reactive;
using System.Reactive.Linq;


class Program
{
    public static IEnumerable<int> fblist(int m)
    {
        for (int i = 1; i <= m; i++) yield return i;
    }
    static void Main(string[] args)
    {
        var fb = fblist(100).ToObservable().Publish();
        fb.Where(c => c % 3 == 0).Subscribe(c => Console.WriteLine("Fizz"));
        fb.Where(c => c % 5 == 0).Subscribe(c => Console.WriteLine("Buzz"));
        fb.Where(c => c % 3 != 0 && c % 5 != 0).Subscribe(c => Console.WriteLine(c.ToString()));
        fb.Connect();
    }
}

とすることも可能。