LINQ 如同 C# 一般,是門易學難精的學問。也或許有人會覺得,要用再查就好啦~ Stackoverflow 滿滿的東西可以挖呢!但問題就在很多時候連關鍵字該怎麼下都想不出來,先記憶一些心法,我想會非常有幫助。細節再 Google 就好,至少關鍵字可以下得出 LINQ 的關鍵字啊!
※ 以下範例程式碼均來自黃忠成老師 skilltree 課程講義範例。
個人心法
- 從集合中巡覽相同的子集合元素:Select Many。
- 將結果切分為更小的元素:Select + Into。
- 單個集合,群組化為「兩層」結構: Group By (+ Into)。
- 兩個集合,交互參照取值,取出「兩層」結構:Join + Into。
- 巡覽各個項目一次,做很多事:Aggregate。
總覽
取值類
- First、Last、Single、ElementAt:(略)。
- FirstOrDefault、LastOrDefault、SingleOrDefault、ElementAtOrDefault:(略)。
取部分集合類
- Select:最後決定要取怎樣的資料出來使用。
- Where:判斷條件式。
- Select Many:從兩個集合中,巡覽一樣型態的子集合。例如兩個部門中,巡覽相同的 Person 型態集合
List<Person>
。Persons var departments = new List<Department> { departmentA, departmentB }; foreach (var p in departments.SelectMany(a => a.Persons)) { Console.WriteLine($"Name : {p.Name}, Age : {p.Age}"); }
- Let :提高 LINQ Expression 的可讀性。
- Select + Into:將結果拆成更細的子項目。
Person2[] data = { new Person2() { ID = 1, Name = "code6421", Age = 10 }, new Person2() { ID = 2, Name = "mary", Age = 11 }, new Person2() { ID = 3, Name = "mark", Age = 12 } }; var result = from s in data where s.Name.Contains('a') select s.Name into p from m in p select m;
'm' 'a' 'r' 'y' 'm' 'a' 'r' 'k'
- DefaultIfEmpty:集合為空,塞入預設值。
- Take、Skip:(略)。
- TakeWhile:符合條件的就取出,一旦遇到不符條件的,就結束。
- SkipWhile:符合條件的就跳過,一旦遇到不符條件的,就放棄比對,後面一律不跳過。
- Except:差集。
- Intersect:交集。
- Union:聯集。
- Distinct:去除重複的項目。
- Concat:串接兩個集合。
- Reverse:反轉集合排序。
- Zip:將兩個集合同樣的 index 項目逐一打包為組合元素。數量較多的集合,後面多出來的項目就忽略。
- ToDictionary:將集合轉為一 key 對應一 Value 的 Dictionary 型態。
- ToLookup:將集合轉換唯一 key 對應多 Value 的 ILookUp 型態。
- ToList:(略)。
- AsEnumerable:轉換為可以用 LINQ 的集合。
- Join:從兩個集合中取出符合條件的項目,後面的 on 接的是條件。
from s1 in data1 join s2 in data2 on s1 equals s2 select s1;
- Join + Into:將兩個集合取出符合條件的項目,並呈現為「兩層」的架構。
原始資料:Department[] deps ={ new Department() { ID = 1, Name = "Developer" }, new Department() { ID = 2, Name = "Sales" }, new Department() { ID = 3, Name = "Support" } }; Employee[] emps = { new Employee() { ID = 1, Name = "code6421", Department_ID = 1 }, new Employee() { ID = 2, Name = "tom", Department_ID = 1 }, new Employee() { ID = 3, Name = "mary", Department_ID = 2 }, new Employee() { ID = 4, Name = "jack", Department_ID = 2 }, };
取出:
foreach (var item in result) { Console.WriteLine($"Department Name : {item.Name}"); foreach (var emp in item.Employees) Console.WriteLine($" Name : {emp.Name}"); }
var result = from s1 in deps join s2 in emps on s1.ID equals s2.Department_ID into emp //emp同emps集合元素的型態 select new { Name = s1.Name, Employees = emp };
- join + into + from + DefaultIfEmpty:可達到 LeftOuterJoin 的效果。
var result = from s1 in emps join s2 in deps on s1.Department_ID equals s2.ID into p1 from s3 in p1.DefaultIfEmpty(new Department() { ID = -1, Name = "(none)" }) select new { EmployeeID = s1.ID, EmployeeName = s1.Name, DepartmentName = s3.Name };
- Group By + ( into ):將單一集合分組,分組後為與 ILookUp 雷同的「兩層」結構。
var result = from s1 in emps group s1 by s1.Department_ID; foreach (var item in result) { Console.WriteLine($"----{item.Key}-----"); foreach (var detail in item) { Console.WriteLine($"Name : {detail.Name}"); } }
統計類
- Min、Max、Avg、Sum:(略)。
- Count、LongCount:(略)。
- Aggregate:巡覽集合的過程中,做很多事。
var result = data.Aggregate(new { Min = int.MaxValue, //回傳的匿名型態,並賦予初始值 Max = int.MinValue }, (x, y) => new { // x為巡覽至此,前面的集合;y為現在被巡覽的值 Min = Math.Min(x.Min, y), //巡覽過程中逐一設定回傳值 Max = Math.Max(x.Max, y) });
- Any:是否有任一符合的項目?
- All:是否所有項目都符合?
其他類
- OfType:可以轉型就轉,不行就略過。
- Repeat:(略)。
- Range:(略)。
- SequenceEqual:(略)。
- PLINQ:平行處理 LINQ。
以上範例程式碼均來自黃忠成老師 skilltree 課程講義範例。