ラムダ式
ラムダ式は一種のメソッドで、メソッドをかなり簡略化することができる。
public void Do() { var numbers = new[] { 5, 3, 9, 6, 7, 5, 8, 1, 0, 5, 10, 4 }; // 変数judgeに処理内容を代入 Predicate<int> judge = (int n) => { if (n % 2 == 0) { return true; } else { return false; } }; // Countメソッドの呼び出し var count = Count(numbers, judge); } // 第2引数のjudgeには、int型を受け取り、bool値を返すメソッドを指定可 public int Count(int[] numbers, Predicate<int> judge) { int count = 0; foreach(var n in numbers) { if(judge(n) == true) { count++; } } return count; }
上記のようなソースがあったとして、変数judgeに代入している処理は、ラムダ式でだいぶ簡略化できる。
- returnの右側には、式を書ける。
- ラムダ式の{}が1つであれば、{}とreturnを省略可。
- 引数の型を明示しなくてもよい。
- 引数が1つであれば、()を省略可。
省略したソースがこちら。
var count = Count(numbers, n => n % 2 == 0);
とかなり省略できるが、ラムダ式は全然慣れてないので、初見だと何をやっているかわからない。また、Predicateの理解も曖昧だし、メソッドの引数にメソッドを指定するって考え方もピンとこない。慣れたら、便利なのかな。
Listクラスとラムダ式の組み合わせ
List
まずは、以下Listがあるとする。
var list = new List<string> { "Tokyo", "New Delhi", "Bankok", "london", "Paris", "Berlin", "Canbera", "Hong Kong" };
このListに対して、ラムダ式を使ったメソッド呼び出し例を記載していく。
Existsメソッド
// 引数で指定した条件に一致する要素がするかをtrue / falseで返却 // 最初の文字が'A'である要素がリスト内に存在するかチェック var exists = list.Exists(s => s[0] == 'A');
Findメソッド
// 引数で指定した条件と一致する要素を検索し、最初に見つかった要素を返却 // 文字列の長さが6文字の最初の要素を返却する(Bankok) var name = list.Find(s => s.Length == 6);
FindIndexメソッド
// 引数で指定した条件と一致する要素を検索し、インデックスを返却 // 要素の中からBerlinを検索し、そのインデックスを返却 int index = list.FindIndex(s => s == "Berlin"); Console.WriteLine(index);
FindAllメソッド
// 引数で指定した条件と一致する、すべての要素を取得する // Tokyo, Parisを取得(文字列が5文字以下) var names = list.FindAll(s => s.Length <= 5); foreach (var s in names) { Console.WriteLine(s); }
RemoveAllメソッド
// 引数で指定した条件と一致すよ要素をリストから削除し、戻り値は削除した要素数 // London, Hong Kongを削除 var removedCount = list.RemoveAll(s => s.Contains("on")); Console.WriteLine(removedCount);
ForEachメソッド
// リストの各要素に対して引数で指定した処理を実行 list.ForEach(s => Console.WriteLine(s)); // 上と下は同じこと foreach(var s in list) { Console.WriteLine(s); }
ConvertAllメソッド
// リスト内の要素を別の型に変換し、変換された要素が格納されたリストを返却
var lowerList = list.ConvertAll(s => s.ToLower());
lowerList.ForEach(s => Console.WriteLine(s));
LINQ to Objectsの基礎
まず、LINQの概要としては、オブジェクト、データベース、XMLなどのさまざまなデータに対して標準化された方法で問い合わせできるというもの。自分の中では、ソースに対して実施できるSQLのイメージできる。(selectやwhereなどがあるから)
また、クエリ演算子はIEnumerable
ここでクエリ演算子の例を一つ。
// Whereで5文字以下の要素に絞り、Selectで、引数にラムダ式で小文字変換を指定し、その結果を出力 IEnumerable<string> query = list.Where(s => s.Length <= 5).Select(s => s.ToLower());
※シーケンスとは
標準クエリ演算子の捜査対象のデータのこと。(配列やList
IEnumerable
遅延実行と即時実行
遅延実行とは、本当にデータが必要になったときにクエリが実行されて、LINQの大きな特徴の一つ。
var list = new List<string> { "Tokyo", "New Delhi", "Bankok", "london", "Paris", "Berlin", "Canbera", "Hong Kong" }; // ここで変数queryに値を代入しているようにみえるが、実際は検索結果が代入されていない var query = list.Where(s => s.Length <= 5); list[0] = "Osaka"; // 値が実際に必要になったタイミングで、クエリ演算子が実行される。 // そのため、実行結果は"Osaka","Paris" foreach(var i in query) { Console.WriteLine(i); }
即時実行とは、クエリを明示的に実行させることをいう。ここでは、ToArrayメソッドを使用した例を示す。
var list = new List<string> { "Tokyo", "New Delhi", "Bankok", "london", "Paris", "Berlin", "Canbera", "Hong Kong" }; // ここで、Whereメソッド実行 var query = list.Where(s => s.Length <= 5).ToArray(); list[0] = "Osaka"; // すでにWhereメソッドが実行されているため、実行結果は"Tokyo","Paris" foreach(var i in query) { Console.WriteLine(i); }