2014年11月12日

C#でn日後を返す関数を返す関数を定義する

   このエントリーをはてなブックマークに追加 Clip to Evernote
どう書く?orgに感謝を込めて」シリーズ その48

■問題 (出題者: にしお さん)
整数nを渡すと「日時のデータを受け取って、n日後の日時を返す関数」を返す関数を作ってください。 関数を返す関数が作れない場合は、関数の代わりになるようなオブジェクトでも構いません。
出題の意図としては「関数を返す関数」と「日時の差分の扱い方」を、それぞれ単体だと簡単すぎるので合わせ技にしてみた、というところです。

「n日後を返す関数」ではなくて、「n日後を返す関数」を返す関数 を定義せよ、という問題です。

C#では、デリゲートを返すメソッドを定義すれば良いということですね。
GetFuncNDaysLater というメソッドを定義し、その戻り値を Func<DateTime, DateTime> デリゲートとしました。
ラムダ式便利ですね。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Doukaku.Org {
    class Program {
        static void Main(string[] args) {
            var FiveDaysLater = GetFuncNDaysLater(5);
            Console.WriteLine("{0:d}", FiveDaysLater(DateTime.Today));
            Console.WriteLine("{0:d}", FiveDaysLater(new DateTime(2014, 12, 27)));
            Console.WriteLine("{0:d}", FiveDaysLater(new DateTime(2038, 1, 30)));
            Console.ReadLine();

        }

        // 「日付を受け取り日付を返す関数」が戻り値なので、
        // 戻り値は、Func<DateTime, DateTime> ですね。
        // ラムダ式は、デリゲートに変換できるので、ラムダ式を返せばよい。
        static Func<DateTime, DateTime> GetFuncNDaysLater(int n) {
            return (DateTime dt) => { return dt.AddDays(n); };
        }

    }
}

  

Posted by gushwell at 23:00Comments(0)TrackBack(0)

2014年11月02日

C#で コメントの削除

   このエントリーをはてなブックマークに追加 Clip to Evernote
どう書く?orgに感謝を込めて」シリーズ その45

■問題 (出題者:nobsun さん)
ソースコードからコメント部分を削除するプログラム decomment を書いてください. すくなくとも,decomment を記述したのと同じ言語で書かれているソースコードが 扱えるようにしてください.

DeComentクラスをStateマシン風に書いてみました。
ただし、Stateクラスを定義するのではなく、delegateで Stateを表現しています。
ラムダ式使えるので、なんかいい感じです。
ちゃんと、C#の文字列リテラルの中の // や、 /* はコメントと認識しなようになってます。
でも、//で始まるコメント行が、削除されずに空白行となるのが、いまいちかな。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace Doukaku.Org {
    public class DeComment {
        delegate void Scan(char c);
        private static string result = "";       
        private static Scan eat;

        private static Scan outComment = (c) => {
            if (c == '/')
                eat = preInComment;
            else {
                if (c == '"')
                    eat = InLiteralString;
                result += c;
            }
        };

        private static Scan preInComment = (c) => {
            if (c == '*')
                eat = inMultiLineComment;
            else if (c == '/')
                eat = inOneLineComment;
            else {
                eat = outComment;
                result += "/" + c;
            }
        };

        private static Scan inOneLineComment = (c) => {
            if (c == '\r' || c == '\n') {
                eat = outComment;
                result += c;
            }
        };

        private static Scan inMultiLineComment = (c) => {
            if (c == '*')
                eat = preOutMultiLineComment;
        };

        private static Scan preOutMultiLineComment = (c) => {
            if (c == '/')
                eat = outComment;
            else
                eat = inMultiLineComment;
        };

        private static Scan InLiteralString = (c) => {
            if (c == '"')
                eat = outComment;
            else if (c == '\\')
                eat = InLiteralStringEscape;
            result += c;
        };

        private static Scan InLiteralStringEscape = (c) => {
            eat = InLiteralString;
            result += c;
        };

        public string Execute(string line) {
            result = "";
            eat = outComment;
            foreach (var c in line) {
                eat(c);
            }
            return result;
        }

    }

}

使い方は、こんな感じ。
ファイルから読み込んだテキストを改行コード込みで、そのまま Decommentクラスの Executeメソッドに渡します。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace Doukaku.Org {
    class Program {
        static void Main(string[] args) {
            var cc = new DeComment();
            var text = File.ReadAllText("Sample.cs");
            var s = cc.Execute(text);
            Console.WriteLine(s);
            Console.ReadLine();
        }
    }

}
  
Posted by gushwell at 22:30Comments(0)TrackBack(0)

2014年08月27日

C#で条件を満たす行を取り除く

   このエントリーをはてなブックマークに追加 Clip to Evernote
どう書く?orgに感謝を込めて」シリーズ その36

久しぶりに、"http://ja.doukaku.org/" にアクセスしたら、Not found になっていました。完全に閉鎖されてしまったようですね。
でも気にせず、このシリーズは続けます(^^;;

■問題 (出題者:にしお さん)
ファイルから1行ずつ読み込み、"#"で始まる行だけを取り除いてファイルに出力するコードを書いてください。
サンプル入力
hello!
# remove this
# don't remove this
bye!

サンプル出力
hello!
# don't remove this
bye!

#"で始まる行だけを取り除くプログラムだとつまらないので、タイトルどおりに「条件を満たす行を取り除くメソッド」を書いてみた。。
つまり条件を引き数として渡せるようにしてみた。

using System;
using System.IO;


namespace Doukaku.Org {
    class Program {
        static void Main(string[] args) {
            RemoveLines("sample.txt", "sampleOut.txt", s => s.StartsWith("#"));
        }       
        private static void RemoveLines(string infile, string outfile, Predicate<string> judge) {
            using (StreamReader sr = new StreamReader(infile))
            using (StreamWriter sw = new StreamWriter(outfile)) {
                while (!sr.EndOfStream) {
                    string s = sr.ReadLine();
                    if (!judge(s))
                        sw.WriteLine(s);
                }
            }
        }
    }
}

この例では、引き数として

  s => s.StartsWith("#")

を渡しているが、

  s => s.Length == 0

とすれば、長さが 0 の行を取り除くことができる。

  
Posted by gushwell at 22:00Comments(0)TrackBack(0)

2012年01月22日

n回処理を繰り返したい (2)

   このエントリーをはてなブックマークに追加 Clip to Evernote
前回「n回処理を繰り返したい (1)」の続きです。

こういった繰り返し処理の時には、何回目の処理かを知りたい場合があります。
そんな時のために、もう一つ拡張メソッドを用意しましょう。


こすれば、次のようなコードが可能になります。


参考に、for文使ったコードも示します。


  
Posted by gushwell at 21:34Comments(0)TrackBack(0)

2012年01月12日

リストのすべての要素に対しラムダ式を適用する

   このエントリーをはてなブックマークに追加 Clip to Evernote
リストをデリゲートが返す値で埋め尽くす では、リストをデリゲート(ラムダ式)の値で初期化する拡張メソッドを
示しましたが、今度は、既にリスト内にセットされている値に対し、ラムダ式を適用し、
新たな値をセットする拡張メソッドを示します。


この拡張メソッドを利用したコードです。

ここでは、各要素を1.05倍しています。
105 210 315 420
がリストの新たな要素となります。

この例では、ラムダ式の第1引数を利用していませんが、この i には、
その要素のインデックス番号がわたるので、そのインデックス値を使って、
要素の値に対し、処理をすることもできます。

ジェネリックなメソッドにしているので、リストの要素が文字列であってもOKです。
まったく、意味のないコードですが、以下にその例を示します。


リストには、順に

 "SILVERLIGHT"
 "INDOWS"
 "OX"
 "ROSOFT"

が格納されます。
  
Posted by gushwell at 22:00Comments(0)TrackBack(0)

2012年01月10日

リストをデリゲートが返す値で埋め尽くす

   このエントリーをはてなブックマークに追加 Clip to Evernote
以前アップした「リストを指定した値で埋め尽くす」をちょっと工夫すれば、さらに汎用性の高い拡張メソッドが作れます。


こんな風に使います。


これで、0 2 4 6 8 10 12 14 16 18 と要素がセットされます。

  
Posted by gushwell at 20:58Comments(2)TrackBack(0)

2010年10月04日

falseとtrueを交互に返す方法(C#)

   このエントリーをはてなブックマークに追加 Clip to Evernote
ネタ元:
a2c.get.diary ■[python] 0と1を次々返す方法
404 Blog Not Found - Algorithm - 0と1を次々と返す簡単なお仕事

すでに旬を過ぎたみたいだけど、C#で僕も書いてみました。

espresso3389の日記 で、espresso3389 さんが素晴らしいコードを紹介しているけど、もう少しオーソドックスな実装で。

true, false を交互に次々と返すようにしています。

でも、これだと、再利用性が低いので、やはりクラスにするべきかな、ということで書いたのがこれ。

dankogaiさんのコードに合わせて、いったんfunc変数に入れてから呼び出しています。
でも、Func<bool> と型を指定するのは面倒です。やはり var を使いたいです。
それと、初期値を設定できないのも、イマイチなので、

としてみました。いわゆる関数を返す関数です。
これならば、var が使えるし、初期値も与えられます。
でも、よくよく考えたら、staticフィールドは、余分ですね。
FlipFlopクラスは、
で、OKでした。
結局、espresso3389 さんのコードと、本質的には大きく変わらないものになってしまいました。
  
Posted by gushwell at 22:27Comments(4)TrackBack(1)

2007年08月17日

C#3.0:ラムダ式

   このエントリーをはてなブックマークに追加 Clip to Evernote
ラムダ式

delegate int MyFunction(int i);

static int Triple(int n) {
return n * 3;
}

static void Test() {
// C#1.1
MyFunction f = new MyFunction(Triple);
int n = f(11);
Console.WriteLine(n);
}

このコードは、delegateの動きを説明した C#1.1のコード。

これが、C#2.0になると、こんな書き方になる。

delegate int MyFunction(int i);

static void Test() {
// C#2.0 匿名メソッド
MyFunction f3 = delegate(int x) { return x * 3; };
n = f3(20);
Console.WriteLine(n);
}

わざわざ Tripleというメソッドを定義する必要がなくなったわけだ。

そして、C#3.0では、

delegate int MyFunction(int i);

static void Ramda() {
// C#3.0 ラムダ式
MyFunction f4 = (int x) => { return x * 3; }; // (*)
n = f4(30);
Console.WriteLine(n);
}

ここまでは、C#2.0 と C#3.0 では、記述方法が変化しただけと見ることもできる。
さらに、

    MyFunction f4 = (int x) => return x * 3;    // (*)

と書ける。さらに、この(*)の記述が、

    MyFunction f4 = (int x) => x * 3;

    MyFunction f4 = (x) => x * 3;

    MyFunction f4 = x => x * 3;

と短くすることができる。

いきなり、最後の文を見せられたときは、いきなり出てきた xって何だ?
と面食らったけど、順番に見ていけば、それほど難しくはない。
でも、慣れるのが大変そう。
  
Posted by gushwell at 20:54Comments(0)TrackBack(2)