こんにちは(/・ω・)/
今回もC#のLinqについての解説です。
前回でもメソッドを少し説明しましたが、今回はより範囲を広げてよく使うものと使えるものを書いていきたいと思います。
-
データの加工
データにフィルター処理をして必要なデータのみを集めたり、データを組み合わせて新しいデータを作ったりすることができます。
サンプルには
int[] numArray = { 1, 2, 3, 4, 5 }; int[] numArray2 = { 1, 1, 1, 2, 3, 5 }; string[] strArray = { "1", "2", "3", "4", "5" }; string[] strArray2 = { "6", "7", "8", "9", "10" };
を使用します。
- Aggregate
アキュムレータ関数を適用する
アキュムレータとは?
例えば、1 + 2 + 3の計算をする時は
- 1 + 2を計算してその計算結果を保存する(結果をAとする)
- A + 3を計算する
のように2つずつ計算をしています。
この計算の過程で出てきたAのような一時的に計算結果を保持しておく領域のことをアキュムレータと言います。
このアキュムレータを使用すると、シーケンスの全要素を計算に利用することができます。
つまり、このメソッドを使用すればシーケンスの全ての要素を使う処理を簡単に書くことができます。
使い方次第で化ける面白いメソッドです。
var aggregate = strArray.Aggregate (( item, item2 ) => item + "☆" + item2); //1☆2☆3☆4☆5 /* * 1.itemと☆とitem2を連結させる * 2.連結した結果がitemになり、次の要素の計算に使用される */
計算結果は第1仮引数に保持されます。(上のサンプルではitemに保持されています)
var aggregate2 = strArray.Aggregate (( item, item2 ) => item2 + " " + item + " " + item2); //5 4 3 2 1 2 3 4 5 var aggregate3 = strArray.Aggregate (( item2, item ) => item2 + " " + item + " " + item2); //1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 5 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1
オーバーロードではシードを設定する必要があります。
シードを設定すると、1回目の計算時のitemが引数で指定したものになります。
var aggregate4 = strArray.Aggregate ("☆", ( item, item2 ) => item + " " + item2); //☆ 1 2 3 4 5
今回紹介する中ではこれが一番難しいと思います。後は大したことないです。
- Select
シーケンスの各要素にラムダ式で指定した処理を行い、新しいシーケンスを作成する
//各要素に2倍したシーケンスを返す var select = numArray.Select (item => item * 2); //2 4 6 8 10 //インデックスを利用したい場合、第2仮引数に変数を宣言します。 var select2 = numArray.Select (( item, index ) => index.ToString () + " " + item * 2); //(0 2), (1 4), (2 6), (3 8), (4 10)
- Skip
引数として受け取った数値分要素を飛ばして、残りのシーケンスを返す
var skip = numArray.Skip (2); //3 4 5
- SkipWhile
ラムダ式で指定した条件を満たしている間シーケンスの要素を飛ばして、満たさなくなったら残りの要素を返す
つまり、条件式がfalseになったら残りの要素を返す
var skipWhile = numArray2.SkipWhile (item => item < 2); //2 3 2 1
- Take
引数として受け取った数値分シーケンスの要素を受け取る
var take = numArray.Take (2); //1 2
- TakeWhile
ラムダ式で指定した条件を満たしている間、シーケンスの要素を返す
満たさなくなったら処理を終了する
つまり、条件式がtrueの間の要素を返す
var takeWhile = numArray2.TakeWhile (item => item < 3); //1 2
- Where
ラムダ式で指定した条件を満たすシーケンスの要素を返す
つまり、trueを通し、falseは通さない
var where = numArray.Where (item => item % 2 == 0); //2 4
- Zip
2つのシーケンスの要素を使用して、新しいデータを作る
2つのシーケンスの要素数が異なる場合、少ない方に合わせる
var zip = strArray.Zip (strArray2, ( item, item2 ) => (item + " " + item2)); //(1 6), (2 7), (3 8), (4 9), (5 10)
SelectとWhereは特に使用する処理なので、覚えておくと便利です。
-
データの集計
サンプルには
int[] numArray = { 1, 2, 3, 4, 5 }; int[] numArray2 = { 1, 1, 1, 2, 3, 5 };
を使用します。
- Average
平均値を求める
var average = numArray.Average (); //シーケンスの平均値を返す //3
- Count
要素の数を求める
var count = numArray.Count (); //要素数を返す //5 var count2 = numArray2.Count (item => item == 1); //条件に合う要素数を返す //3
- Max
最大値を求める
var max = numArray.Max (); //シーケンスの最大値を返す //5
- Min
最小値を求める
var min = numArray.Min (); //シーケンスの最小値を返す //1
- Sum
合計を求める
var sum = numArray.Sum (); //シーケンスの合計値を返す //15
特に複雑な操作は必要ありません。また、ラムダ式で指定すれば、絶対値で計算したりすることができます。
-
データの型変換
サンプルには
int[] numArray = { 1, 2, 3, 4, 5 };
を使用します。
- ToArray
IEnumerable<T>からT[]に変換する
var toArray = numArray.Take (2).ToArray (); Console.WriteLine (toArray.GetType ().ToString ()); //System.Int32[]
- ToList
IEnumerable<T>からList<T>に変換する
var toList = numArray.ToList (); Console.WriteLine (toList.GetType ().ToString ()); //System.Collections.Generic.List'1[System.Int32]
型変換についてはこの2つを使えるようになれれば、特に問題はないと思います。
-
データの判定
このような状況の時にLinqメソッドで書き換えることができます。
foreach (var item in コレクション) { if (条件) { //処理 } }
サンプルには
bool[] trueArray = { true, true, true }; bool[] boolArray = { true, false, true }; int[] numArray = { 1, 2, 3, 4, 5 };
を使用します。
- All
シーケンスの全ての要素がラムダ式で指定した条件を満たしているか
var all = trueArray.All (item => item == true); //true
- Any
シーケンスのどれかの要素がラムダ式で指定した条件を満たしているか
var any = boolArray.Any (item => item == false); //true
- Contains
指定した要素がシーケンスに含まれているかどうか
var contains = numArray.Contains (1); //1があるかどうか //true
-
データの集合
和集合、積集合、差集合の3つが扱えます。
サンプルには
int[] numArray = { 1, 2, 3, 4, 5 }; int[] oddArray = { 1, 3, 5, 7, 9 }; int[] evenArray = { 2, 4, 6, 8, 10 };
を使用します。
- Union
2つのシーケンスから和集合を求める
var union = oddArray.Union (evenArray); //和集合 //1 3 5 7 9 2 4 6 8 10
- Intersect
2つのシーケンスから積集合を求める
var intersect = numArray.Intersect (evenArray); //積集合 //2 4
- Except
左のシーケンスから右のシーケンスを除いた差集合を求める
var except = numArray.Except (oddArray); //差集合 奇数を取り除く //2 4 var except = oddArray.Except (numArray); //1~5の要素を取り除く //7 9
-
データのソート
サンプルには
var dataArray = new[] { new { A = 1, B = 1 }, new { A = 2, B = 2 }, new { A = 3, B = 2 }, new { A = 2, B = 3 }, new { A = 1, B = 0 } };
を使用します。
- OrderBy
昇順に並び替える
//Aを基準に昇順で並び替える var orderBy = dataArray.OrderBy (item => item.A); //結果 {1 1}{1 0}{2 2}{2 3}{3 2}
- OrderByDescending
降順に並び替える
//Aを基準に降順で並び替える var orderByDescenging = dataArray.OrderByDescending (item => item.A); //結果 {3 2}{2 2}{2 3}{1 1}{1 0}
- ThenBy
昇順に並び替える
ただし、OrderByもしくはOrderByDescendingの後でないと使用できない
//Aを基準に昇順で並び替える、ただしAの値が同じ場合、Bの値を比較して昇順で並び替える。 var thenBy = dataArray.OrderBy (item => item.A).ThenBy (item => item.B); //結果 {1 0}{1 1}{2 2}{2 3}{3 2}
- ThenByDescending
降順に並び替える
ただし、OrderByもしくはOrderByDescendingの後でないと使用できない
//Aを基準に昇順で並び替える。ただしAの値が同じ場合、Bの値を比較して降順で並び替える。 var thenByDescenging = dataArray.OrderBy (item => item.A) .ThenByDescending (item => item.B); //結果 {1 1}{1 0}{2 3}{2 2}{3 2}
- Reverse
順序を逆にする
var reverse = dataArray.Reverse (); //結果 {1 0}{2 3}{3 2}{2 2}{1 1}
ThenByとThenByDescendingに関しては、それらの後ろにThenBy、ThenByDescendingを使うことによって、第3以降の並び替えの基準を設定することができます。
ソートに関してはかなり便利で、どんなデータ構造を持っているクラスであっても簡単にソートができるようになります。
-
データの探索
指定した要素を探して返す処理ができます。
サンプルには
int[] numArray = { 1, 2, 3, 4, 5 };
を使用します。
- ElementAt
- ElementAtOrDefault
引数として渡したインデックス位置にある要素を返す
引数が配列外の値だった場合、ElementAtは例外を投げ、ElementAtDefaultは型の規定値を返す(例えばintの規定値は0)
var elementAt = numArray.ElementAt (1); //2 var elementAtDefault = numArray.ElementAtOrDefault (5); //0
- First
- FirstOrDefault
シーケンスの最初の要素を返す
もしくは、条件を満たす最初の要素を返す
シーケンスに要素がない場合、Firstは例外を投げ、FirstOrDefaultは型の規定値を返す
var first = numArray.First (item => item % 2 == 0); //2 var firstOrDefault = numArray.FirstOrDefault (); //1
- Last
- LastOrDefault
シーケンスの最後の要素を返す
もしくは、条件を満たす最後の要素を返す
シーケンスに要素がない場合、Lastは例外を投げ、LastOrDefaultは型の規定値を返す
var last = numArray.Last (item => item % 2 == 0);//4 var lastOrDefault = numArray.LastOrDefault (item => item == 7); //0
C#はなかなか奥が深い(~_~;)
他にもメソッドはありますが、(特にゲーム系のプログラミングでは)あまり使わないと思います。
一度サンプルを書いてみるとよく覚えられます
では(^_^)/