C# Linq Join 詳解

一、Linq Join基礎介紹

Linq Join是一種常用的Linq查詢方法之一,主要用於在兩個集合中根據條件聯接元素。Linq Join可以將兩個集合中的元素以特定條件進行匹配,從而得到一個新的結果集合。

例如,我們可以使用Linq Join將兩個學生集合中的成績進行匹配,得到一張包含學生名字和成績的新表。下面是一個基本的Linq Join用法的示例:

    List studentList = new List()
    {
        new Student() { Name = "Tom", Grade = "Grade 1" },
        new Student() { Name = "Jerry", Grade = "Grade 2" },
        new Student() { Name = "Mary", Grade = "Grade 1" },
        new Student() { Name = "Bob", Grade = "Grade 3" }
    };

    List scoreList = new List()
    {
        new Score() { Name = "Tom", Grade = 90 },
        new Score() { Name = "Jerry", Grade = 80 },
        new Score() { Name = "Mary", Grade = 85 },
        new Score() { Name = "Bob", Grade = 95 }
    };

    var queryResult = from student in studentList
                      join score in scoreList on student.Name equals score.Name
                      select new { Name = student.Name, Grade = score.Grade };

    foreach (var item in queryResult)
    {
        Console.WriteLine("Name:{0}, Grade:{1}", item.Name, item.Grade);
    }

上述示例中,我們定義了兩個實體類Student和Score,分別代表學生和成績。然後我們定義了兩個列表studentList和scoreList存儲學生和成績信息。在使用Linq Join時,我們以學生姓名作為條件進行匹配,從而得到一個包含學生姓名和成績的新結果集queryResult。最後我們輸出新結果集中的元素。

二、Join的幾種類型

除了上述基本用法外,Linq Join還有幾種不同類型,分別是Inner Join、Left Join、Right Join和Full Join。

1. Inner Join

Inner Join是Linq Join的默認類型,它只返回兩個集合中匹配的元素。如果一個元素在一個集合中找不到對應元素,則不會被包含在結果集中。

以下代碼是Inner Join的示例:

    var innerJoinResult = from student in studentList
                          join score in scoreList on student.Name equals score.Name
                          select new { Name = student.Name, Grade = score.Grade };

2. Left Join

Left Join會返回第一個集合的所有元素,而不僅僅是匹配的元素。如果一個元素在第二個集合中找不到對應元素,則其對應的值為null。以下是Left Join示例:

    var leftJoinResult = from student in studentList
                         join score in scoreList on student.Name equals score.Name into gj
                         from subScore in gj.DefaultIfEmpty()
                         select new { Name = student.Name, Grade = subScore?.Grade };

3. Right Join

Right Join是Left Join的反向操作,它返回第二個集合的所有元素,而不是第一個集合的所有元素。以下是Right Join示例:

    var rightJoinResult = from score in scoreList
                          join student in studentList on score.Name equals student.Name into gj
                          from subStudent in gj.DefaultIfEmpty()
                          select new { Name = subStudent?.Name, Grade = score.Grade };

4. Full Join

Full Join返回所有的元素,除了完全沒有匹配的元素以外,沒有匹配的元素對應的值為null。以下是Full Join示例:

    var fullJoinResult = from student in studentList
                         join score in scoreList on student.Name equals score.Name into gj
                         from subScore in gj.DefaultIfEmpty()
                         select new { Name = student?.Name, Grade = subScore?.Grade };

三、Join的性能優化

Linq Join可以處理不同大小的集合,但是當集合的大小差別很大時,Join的性能可能會受到影響。

為了進一步了解Join的性能問題,我們可以分別測試以下幾種情況:

1. List和Dictionary的Join

對於如下代碼:

    List list = Enumerable.Range(0, 10000).ToList();
    Dictionary dict = Enumerable.Range(5000, 10000).ToDictionary(key => key);

    var res1 = from l in list
               join d in dict on l equals d.Key
               select d.Value;

我們可以看到結果res1是一個IEnumerable的集合。

可以發現,在List和Dictionary進行Join時,Linq使用了Hash Join算法,這種算法能夠在O(n)的時間複雜度下完成Join操作,比Nest Join算法快得多。其原理為:首先將需要Join的兩個表按照Join條件分別進行Hash映射,然後判斷兩個表中Hash值相等的記錄是否滿足Join條件。

2. Dictionary和Dictionary的Join

對於如下代碼:

    Dictionary dict1 = Enumerable.Range(0, 10000).ToDictionary(key => key);
    Dictionary dict2 = Enumerable.Range(5000, 10000).ToDictionary(key => key);

    var res2 = from d1 in dict1
               join d2 in dict2 on d1.Key equals d2.Key
               select new { d1.Key, Value1 = d1.Value, Value2 = d2.Value };

我們可以看到結果res2是一個IEnumerable的集合。

可以發現,在Dictionary和Dictionary進行Join時,Linq使用了Nested Loop Join算法,這種算法的時間複雜度為O(n*m)。當m和n的大小差距很大時,Join的性能會變得很差。

3. List和List的Join

對於如下代碼:

    List list1 = Enumerable.Range(0, 10000).ToList();
    List list2 = Enumerable.Range(5000, 10000).ToList();

    var res3 = from l1 in list1
               join l2 in list2 on l1 equals l2
               select l1;

我們可以看到結果res3是一個IEnumerable的集合。

可以發現,當List和List進行Join時,Linq使用了簡單的Nested Loop Join算法。如果兩個集合中存在重複元素,會增加Join操作的時間複雜度,因此建議在進行Join時,將重複元素進行去重。

四、Join的複雜實例

以下是一個較為複雜實例的代碼示例,其目的是通過Join操作得到兩個表的笛卡爾積和總和:

    List list1 = Enumerable.Range(0, 10).ToList();
    List list2 = Enumerable.Range(10, 10).ToList();

    var query = from l1 in list1
                from l2 in list2
                join l3 in list2 on l1 equals l3 into gj
                from subL3 in gj.DefaultIfEmpty()
                select new
                {
                    L1 = l1,
                    L2 = l2,
                    L3 = subL3
                };

    var cartesianProd = query.Count();
    var sum = query.Sum(x => x.L1 + x.L2 + (x.L3 == null ? 0 : x.L3));

五、總結

本文詳細介紹了Linq Join的基礎概念、幾種Join類型、性能問題和複雜實例,希望讀者能夠掌握Linq Join的使用,並在實際開發中靈活運用。

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/240196.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-12 12:20
下一篇 2024-12-12 12:20

相關推薦

  • Python中字符串join方法解析

    join是一個非常實用的字符串方法,它可以用於將序列中的元素連接成一個字符串。以下是關於Python中字符串join方法的詳細解析。 一、基本使用 join方法是在一個字符串列表或…

    編程 2025-04-27
  • Linux sync詳解

    一、sync概述 sync是Linux中一個非常重要的命令,它可以將文件系統緩存中的內容,強制寫入磁盤中。在執行sync之前,所有的文件系統更新將不會立即寫入磁盤,而是先緩存在內存…

    編程 2025-04-25
  • 神經網絡代碼詳解

    神經網絡作為一種人工智能技術,被廣泛應用於語音識別、圖像識別、自然語言處理等領域。而神經網絡的模型編寫,離不開代碼。本文將從多個方面詳細闡述神經網絡模型編寫的代碼技術。 一、神經網…

    編程 2025-04-25
  • C語言貪吃蛇詳解

    一、數據結構和算法 C語言貪吃蛇主要運用了以下數據結構和算法: 1. 鏈表 typedef struct body { int x; int y; struct body *nex…

    編程 2025-04-25
  • Python輸入輸出詳解

    一、文件讀寫 Python中文件的讀寫操作是必不可少的基本技能之一。讀寫文件分別使用open()函數中的’r’和’w’參數,讀取文件…

    編程 2025-04-25
  • nginx與apache應用開發詳解

    一、概述 nginx和apache都是常見的web服務器。nginx是一個高性能的反向代理web服務器,將負載均衡和緩存集成在了一起,可以動靜分離。apache是一個可擴展的web…

    編程 2025-04-25
  • MPU6050工作原理詳解

    一、什麼是MPU6050 MPU6050是一種六軸慣性傳感器,能夠同時測量加速度和角速度。它由三個傳感器組成:一個三軸加速度計和一個三軸陀螺儀。這個組合提供了非常精細的姿態解算,其…

    編程 2025-04-25
  • Python安裝OS庫詳解

    一、OS簡介 OS庫是Python標準庫的一部分,它提供了跨平台的操作系統功能,使得Python可以進行文件操作、進程管理、環境變量讀取等系統級操作。 OS庫中包含了大量的文件和目…

    編程 2025-04-25
  • Java BigDecimal 精度詳解

    一、基礎概念 Java BigDecimal 是一個用於高精度計算的類。普通的 double 或 float 類型只能精確表示有限的數字,而對於需要高精度計算的場景,BigDeci…

    編程 2025-04-25
  • Linux修改文件名命令詳解

    在Linux系統中,修改文件名是一個很常見的操作。Linux提供了多種方式來修改文件名,這篇文章將介紹Linux修改文件名的詳細操作。 一、mv命令 mv命令是Linux下的常用命…

    編程 2025-04-25

發表回復

登錄後才能評論