素敵な夜ですね。
C#勉強中なので自分用にLINQを纏めました。
LINQとは
デリゲード
まずデリゲードという記法について記述する。
配列arrayと数字nを受け取り、arrayで値がnとなっている要素の個数を調べるメソッドを考える。
public long Count(long[] array,long n){ long x = 0; foreach(long y in arr){if(y==n※1) x++;} return y;}
全角※1の部分を引数にしたい。これを可能とするのがデリゲード。
public delegate bool Del(long n){return n==42;}; public long Count(long[] array,long n){ long x = 0; foreach(long y in arr){if(del(y) == true) x++;} return y;}
このDelとCountを
Judgement judge = Del; var c = Count(array,judge);
だったり
var c = Count(array,Del);
と使う。
匿名メソッド
C#2.0から、Delメソッドを省略できるようになった。
public long Count(long[] arr,Predicate<long> predi){ long x = 0; foreach(long y in array){if(predi(y) == true) x++;} return y;} public void Main(){ var c = Count(array,delegate(int x){return x == 42;}); }
Predicateは、任意の数の引数を取りBooleanを返すメソッド(へのデリゲード)を表す型。
ラムダ式
C#3.0で、匿名メソッドと似た記述を更に進化・簡略化して行えるようになった。
Predicate<int> predi = (int x) => {if(x == 42){return true;}else{return false;}}; var c = Count(array,predi);
上記コードの一行目がラムダ式。引数宣言の後、その後で評価を行う一種のメソッド。
そしてこれを更に簡略化する。言語機能上、わざわざ変数宣言する必要がない。
var c = Count(array,(int x) => {if(x == 42){return true;}else{return false;});
そしてこれを更に簡略化する。式はそれ自体がbool型の値とみなせる。
var c = Count(array,(int x) => { return x == 42;});
そしてこれを更に簡略化する。一つのラムダ式に一つの文しかない時は、中括弧とreturnとセミコロンが不要。
var c = Count(array,(int x) => x == 42);
そしてこれを更に簡略化する。型を推論してくれる為型の明示不要。引数が一つの場合は括弧の省略可。
var c = Count(array,x => x == 42);
つまり、ラムダ式の(左辺) => (右辺)は(引数宣言) => (returnを省略した評価値)である。
TIPS
ラムダ式でたまに見る気がするメソッド
・Exists
・FindAll 戻り値はList
・RemoveAll
・ConvertAll
LINQでたまに見る気がするメソッド
・Where(遅延)
・Select(遅延)
・Join(遅延)
・OrderBy/OrderByDecending(遅延)
・Reverse(遅延)
・First/FirstorDefault,Last/LastOrDefault(即時)
・Max,Min,Sum(即時)
・ToArray,ToDicitonary,ToList,ToLookup(即時)
戻り値について
遅延とカッコ書きされたLINQメソッドの戻り値はIEnumerable
一言でいうと特殊な状態となる。Foreachならそのまま使える。
即時実行、遅延実行について
LINQのメソッドは(言わば)値ではなく式を代入する遅延実行と呼ばれる挙動を示すものが多い。
恐らく、要素全体を変化させたりして再度返すものは遅延実行、要素から特定要素を取り出したり一意の値を導き出して返すものは即時実行に見える。
言い換えると、特定のLINQメソッドは毎回再評価される。
string[] array = {"a","b","c","ab","bc","ac"} var li = array.Where(s => s.Length>1); foreach(var s in li){Console.WriteLine(s);} array[0] = "abc" foreach(var s in li){Console.WriteLine(s);}
多分実行結果はab,bc,acとabc,ab,bc,acになる。
これを避けるにはToArray等で固定する。
string[] array = {"a","b","c","ab","bc","ac"} var li = array.Where(s => s.Length>1).ToArray; foreach(var s in li){Console.WriteLine(s);} array[0] = "abc" foreach(var s in li){Console.WriteLine(s);}
多分実行結果はab,bc,acとab,bc,acになる。
メリットがわからない。なぜ即時実行、遅延実行という概念が存在するのか? => ネットに発見できず
indexの値を引っ張るLINQ
long sumOfOdd = a.Where((b, index) => index % 2 != 0).Sum();
参考文献 アフィはありません
実戦で役立つC#プログラミングの定石&パターン
www.amazon.co.jp
現在岸原オカルト研究部では、黒魔術(C#)を研究しています。
twitter:@kisihara_c
他のオカルト研究↓
超インスタント競プロ環境構築 C# - 岸原オカルト研究部