LINQ 學習之路

来源:https://www.cnblogs.com/baiye123/archive/2023/08/22/17647997.html
-Advertisement-
Play Games

## 一、為什麼要使用 LINQ 要理解為什麼使用 LINQ,先來看下下麵的例子 例子:要統計字元串中每個字母出現的頻率(忽略大小寫),然後按照從高到低的順序輸出出現頻率高於2次和其出現的的頻率。如果用傳統的 Sql 語句來寫,一定是非常的繁雜,如果用 LINQ 語句來寫,效果如下 ```c# st ...


一、為什麼要使用 LINQ

要理解為什麼使用 LINQ,先來看下下麵的例子

例子:要統計字元串中每個字母出現的頻率(忽略大小寫),然後按照從高到低的順序輸出出現頻率高於2次和其出現的的頻率。如果用傳統的 Sql 語句來寫,一定是非常的繁雜,如果用 LINQ 語句來寫,效果如下

string strs = "hello word, Hehehe";
var items = strs.Where(c => char.IsLetter(c)) //過濾非字元
            .Select(c => char.IsLower(c))  //大小寫都轉換成小寫
            .GroupBy(c => c) //根據字母進行分組
            .Where(g => g.Count() > 2) //過濾掉出現次數 <=2
            .OrderByDescending(g => g.Count()) //按次數排序
            .Select(g => new { Char = g.Key, Count = g.Count() });

使用 Linq 來實現,簡單、清晰、明瞭。這裡就體現了 LINQ 的一大好處:讓數據處理變得簡單

二、揭秘 LINQ 方法的背後

瞭解 LINQ 方法背後做了些什麼,可以讓我們更好的使用 LINQ。下麵以 Wherr 方法為例,寫一個我們自己的 MyWhere 方法

LINQ 提供了很多集合的擴展方法,配合 lambda 能簡化數據處理

例子:有一個 [3, 15, 88, 4, 77, 42, 8] 的數組,要得到它 >10 的值

int[] num = new int[] { 3, 15, 88, 4, 77, 42, 8 };
//使用原本的Where
IEnumerable<int> result = num.Where(r => r > 10);
foreach (int i in result)
{
    Console.WriteLine(i);
});
}
static void Main(string[] args)
{
    int[] num = new int[] { 3, 15, 88, 4, 77, 42, 8 };
    //使用我們自己寫的MyWhere方法
    var result2 = MyWhere2(num, r => r > 10);
    foreach (int i in result2)
    {
        Console.WriteLine(i);
    }           
}
public static IEnumerable<int> MyWhere(IEnumerable<int> items, Func<int, bool> f)
{
    List<int> result = new List<int>();
    foreach (var i in items)
    {
        if (f(i) == true)
        {
            result.Add(i);
        }
    }
    return result;
}

在上述代碼中,MyWhere 方法是根據我們的需求來寫的一個擴展方法,它要求傳入一個IEnumerable 類型的參數和一個 Func<int,bool> 委托類型的參數,在方法中,新建一個 List 集合用於存值,遍歷傳入的數組,符合條件就存入集合中,最後返回集合。

三、LINQ 的擴展方法

LINQ 關鍵的功能是提供了集合類的擴展方法,所以實現了 IEnumerable 介面的類都可以使用這些方法,這是方法並不是 IEnumerable 中的方法,而是以擴展方法的存在於System.Linq 命名空間的靜態類中

準備一些測試數據

class Employee
{
    public long Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public bool Gender { get; set; }
    public int Salary { get; set; }
    public override string ToString()
    {
        return $"Id={Id},Name={Name},Age={Age},Gender={Gender},Salary={Salary}";
    }
}

Where(數據過濾)

Where 方法是根據條件對數據進行過濾

語法如下:

IEnumerable<Employee> items = list.Where(e => e.Age > 25);
foreach (var item in items)
{
    Console.WriteLine(item);
}

Count(獲取數據條數)

語法如下:

 //返回一個數字,表示指定序列中滿足條件的元素個數。
 Console.WriteLine(list.Count(e => e.Salary > 5000 || e.Age > 25));

Any(判斷是否有一條數據滿足條件)

語法如下:

//是否至少有一條數據
//性能比 Count 要高,Count 會遍歷所有數據才返回結果,Any 在遍曆數據時遇到滿足條件的數據就直接返回結果
Console.WriteLine(list.Any(e => e.Salary == 8000));
Console.WriteLine(list.Where(e=>e.Salary>8000).Any());

Single、SingleOrDefault、First、FirstOrDefault(獲取一條數據)

語法如下:

//有且只有一條數據,如果沒有符合條件的數據或者存在大於一條符合條件的數據,都會報錯
Console.WriteLine(list.Single(s => s.Name == "張德開"));
//有且只有一條數據,返回該條數據,否則返回預設值,如果匹配到多條數據,則會報錯
Console.WriteLine(list.SingleOrDefault(s => s.Age == 18));
//匹配到多條數據時,返回第一條數據,沒有匹配到數據時,則會報錯
Console.WriteLine(list.First(e => e.Age > 30));
//匹配到多條數據時,返回第一條數據,否則返回預設值
Console.WriteLine(list.FirstOrDefault(e => e.Age > 30));

OrderBy、OrderByDescending(排序)

語法如下:

 //升序排序
 IEnumerable<Employee> e = list.OrderBy(s => s.Age);
 //降序排序
 e = list.OrderByDescending(s => s.Salary);
 e = list.OrderByDescending(s => s.Name[s.Name.Length - 1]);
 //可以在OrderBy、OrderByDescending後面繼續使用ThenBy、ThenByDescending進行多規則排序
 e = list.OrderBy(s => s.Age).ThenBy(s => s.Salary);
 foreach (var item in e)
 {
     Console.WriteLine(item);
 }

Sike()、Take()(限制結果集)

語法如下:

// Skip(n) 跳過 n 條數據,Take(n) 獲取 n 條數據
var items2 = list.Skip(3).Take(2);
items2 = list.Where(e => e.Age >= 25).OrderBy(e => e.Age).Skip(2).Take(3);
foreach (var item in items2)
{
 Console.WriteLine(item);
}

聚合函數

Max(最大值)、Min(最小值)、Average(平均值)、Sun(總和)、Count(總數)

語法如下:

//最大年齡
Console.WriteLine(list.Max(e => e.Age));
//最低工資
Console.WriteLine(list.Min(e => e.Salary));
//平均工資
Console.WriteLine(list.Average(e => e.Salary));
//所有人總工資
Console.WriteLine(list.Sum(e => e.Salary));
//女員工數量
Console.WriteLine(list.Count(e => e.Gender == false));

GroupBy(分組)

GroupBy 方法的參數 keySelector 是分組條件表達式,GroupBy 方法的返回值為IGrouping<TKey, TSource> 類型的泛型 IEnumerable。IGrouping 是繼承自 IEnumerable的介面,IGrouping 中唯一的成員就是 Key 屬性,表示這一組數據的數據項,由於IGrouping 是繼承自 IEnumerable 介面的,因此我們依然可以使用 Count、Min、Average等方法對組內數據進行聚合運算

語法如下:

 //根據年齡進行分組
 IEnumerable<IGrouping<int, Employee>> items3 = list.GroupBy(e => e.Age);
 foreach (IGrouping<int, Employee> g in items3)
 {
     Console.WriteLine(g.Key);
     foreach (Employee e in g)
     {
         Console.WriteLine(e);
     }
 }

綜合案例:

//根據年齡分組,獲取每組人數,最大工資,平均工資,用var簡化編程
var item3 = list.GroupBy(e => e.Age);
foreach (var g in item3)
{
    Console.WriteLine("每組人數:" + g.Count());
    Console.WriteLine("最大工資:" + g.Max(e => e.Salary));
    Console.WriteLine("平均工資:" + g.Average(e => e.Salary));
    foreach (var e in g)
    {
        Console.WriteLine(e);
    }
}

Select(投影)

可以對集合使用 Select 方法進行投影操作,通俗來講就是把集合中的每一項逐漸轉換為另外一種類型,Select 方法的參數是轉換的表達式。

語法如下:

//把集合中的每一項轉換成另一個類型
var items4 = list.Select(e => e.Age);
//Select 方法把 bool 的 Gender 轉換為字元串類型,Select 方法的返回值為 IEnumerable<string> 類型
var items4 = list.Where(e => e.Salary > 5000).Select(e => e.Gender ? "男" : "女");
//根據年齡分組,然後統計各組人數、年齡、最高工資、最低工資
var items4 = list.GroupBy(e => e.Age).Select(s => new { NianLing = s.Key, MaxS = s.Max(e => e.Salary), MinS = s.Min(e => e.Salary), RenShu = s.Count() });
foreach (var e in items4)
{
    Console.WriteLine(e.NianLing + ',' + e.MaxS + "," + e.MinS + ',' + e.RenShu);
}

集合轉換

語法如下:

// ToList() 將其他類型轉換為 List<T> 類型
List<Employee> empList = list.Where(e => e.Age > 25).ToList();
// ToArray() 將其他類型轉換為數組
Employee[] empArr = list.Where(e => e.Salary > 5000).ToArray();

鏈式調用

上述介紹的這些方法,Where、Count、OrderBy、GroupBy 等方法的返回值都是 IEnumerable 類型,因此它們是可以鏈式調用的

//獲取 id>2 的數據,然後按照 Age 分組,並且把分組按照 Age 排序,然後取出前三條,最後再投影取得年齡、人數、平均工資
var items5 = list.Where(e => e.Id > 2).GroupBy(g => g.Age).OrderBy(g => g.Key).Take(3)
                .Select(e => new { LianLin = e.Key, renShu = e.Count(), pingJun = e.Average(e => e.Salary) });
foreach (var i in items5)
{
    Console.WriteLine(i.pingJun + "," + i.renShu + "," + i.pingJun);
}

四、LINQ 的另一種寫法

LINQ 有兩種語法,分別為方法語法和查詢語法

//方法語法:使用Where、OrderBy、Selsect等擴展方法來查詢數據的寫法叫做Linq方法語法
var items6 = list.Where(e => e.Salary > 3000).OrderBy(e => e.Age)
                .Select(e => new { e.Name, e.Age, XB = e.Gender ? "男" : "女" });
//查詢語法:使用 LINQ 聲明性查詢語法編寫的查詢語句,在編譯代碼時,查詢語法必須轉換為針對.Net公共語言的的調用,這些方法的調用會調用標準查詢運算符
var items7 = from e in list
             where e.Salary > 3000
             orderby e.Age
             select new
             {
                 e.Name,
                 e.Age,
                 XB = e.Gender ? "男" : "女"
             };

方法語法

“方法語法” 並沒有發明新的語法,用的都是擴展方法、Lambda 表達式等 C# 中已經存在的語法,而 “查詢語法” 則是新的 C# 語法 。編譯器會把 “查詢語法” 編譯成 “方法語法” 形式,因此它們在運行時沒有區別。所有的 “查詢語法” 都能改寫成 “方法語法”,所有的 “方法語法”也能改寫成 “查詢語法” 。

查詢語法

“查詢語法” 看起來更加新穎,而且比 “方法語法” 需要寫的代碼會少一點,但在編寫複雜的查詢條件的時候,用 “方法語法” 編寫的代碼會更清晰

五、小練習

練習一

"85,34,23,45,12,67,60" 計算這些數的平均值

 string s = "85,34,23,45,12,67,60";
 var avg = s.Split(',').Select(e => Convert.ToInt32(e)).Average();
 Console.WriteLine(avg);

練習二

統計一個字元串中每個字母出現的頻率(忽略大小寫),然後按照從高到低的順序輸出出現頻率高於2次的單詞和出現的頻率

string s = "Hello word Hehehe Hahaha";
var items7 = s.Where(e => char.IsLetter(e)).Select(e => char.ToLower(e)).GroupBy(c => c)
    .Select(g => new { g.Key, Count = g.Count() }).OrderBy(g => g.Count).Where(g => g.Count > 2);
foreach (var item in items7)
{
    Console.WriteLine(item);
}

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 需求背景 需要在前端頁面展示當前表欄位的所有上下游血緣關係,以進一步做數據診斷治理。大致效果圖如下: 首先這裡解釋什麼是表欄位血緣關係,SQL 示例: CREATE TABLE IF NOT EXISTS table_b AS SELECT order_id, order_status FROM t ...
  • 由於本人太弱,可能講解有誤,請讀者指出。 # 什麼是網路流 網路流是通過構建從源點到匯點的有向圖模型來解決圖論問題。從理論上講,網路流可以處理所有二分圖問題。 二分圖和網路流的難度都在於問題建模,一般不會特意去卡演算法效率,所以只需要背一兩個簡單演算法的模板就能應付大部分題目了。 # 最大流問題 ## ...
  • 1.已解密的登錄請求 推理: AppScan 識別了不是通過 SSL 發送的登錄請求。 測試請求和響應: 1.1.1 產生的原因 登錄介面,前端傳入的密碼參數沒有經過md5的加密就直接傳給了後端 1.1.2 解決方法 前端代碼傳參的時候做md5加密處理 2.會話標識未更新 推理: 測試結果似乎指示存 ...
  • ### 1. 建立工程 bh003_ble [源碼](https://github.com/densen2014/BlazorHybrid/tree/master/bh100days/bh003_ble?WT.mc_id=DT-MVP-5005078) ### 2. 添加 nuget 包 ``` ` ...
  • ## zhontai 項目 > 基於 .Net7.x + Vue 等技術的前後端分離後臺許可權管理系統,想你所想的開發理念,希望減少工作量,幫助大家實現快速開發 後端地址:https://github.com/zhontai/Admin.Core 前端地址:https://github.com/zho ...
  • 最近建立一個新項目準備寫一個小demo,新建項目時選的時.Net7。寫代碼的時候發現。Net7沒有系統的中文註釋,去官網下載的時候發現沒有關於.Net7的漢化文件包,最新的漢化包是。Net5的,可能是我沒找到,我這裡是把.Net5漢化包放到了.Net7下麵了,測試好用。 一、.NET Framewo ...
  • # C#文本轉語音(科大訊飛離線版) ### 引言 文本轉語音(Text To Speech),簡稱TTS,在很多業務場景會用到,比如廣播大廳,人機互動等。C#要實現TTS有不少選擇,比如調用System.Speech,此處就不細說了,下麵主要介紹一下C#調用科大訊飛的離線語音合成SDK來實現文本轉 ...
  • 本文主要介紹SignalR在實際項目中的應用,以及.NET Framework和.NET Core中如何去使用SignalR。SignalR是一個開放源代碼庫,可用於簡化嚮應用添加實時Web功能,實時Web功能使伺服器端代碼能夠將內容推送到客戶端。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...