[LINQ] C# LINQ 關鍵字筆記

  • 5185
  • 0
  • 2017-11-19

LINQ 如同 C# 一般,是門易學難精的學問。也或許有人會覺得,要用再查就好啦~ Stackoverflow 滿滿的東西可以挖呢!但問題就在很多時候連關鍵字該怎麼下都想不出來,先記憶一些心法,我想會非常有幫助。細節再 Google 就好,至少關鍵字可以下得出 LINQ 的關鍵字啊!

※ 以下範例程式碼均來自黃忠成老師 skilltree 課程講義範例。

個人心法

  1. 從集合中巡覽相同的子集合元素:Select Many
  2. 將結果切分為更小的元素:Select + Into
  3. 單個集合,群組化為「兩層」結構: Group By (+ Into)
  4. 兩個集合,交互參照取值,取出「兩層」結構:Join + Into
  5. 巡覽各個項目一次,做很多事: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}");
    }
    其中 into 的型態為 join 後面項目的型態。
    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 課程講義範例。