背景
傳統上,針對數據的查詢都以簡單的字符串表示,而沒有編譯時類型檢查或 IntelliSense 支持。此外,還需要針對每種數據源學習一種不同的查詢語言:SQL 數據庫、XML 文檔、各種 Web 服務等等。 LINQ 使查詢成為 C# 中的一流語言構造。 可以使用語言關鍵字和熟悉的運算符針對強類型化對象集合編寫查詢。
注意事項
版本需求:.NET Framework 3.5 或更高版本
查詢對象:SQL Server 數據庫、XML 文檔、ADO.NET 數據集以及支持 IEnumerable 或泛型 IEnumerable<T> 接口的任何對象集合
引用包:System.Linq
以下按照使用度排序介紹。
Where
用於過濾數據,減少IF分支語句。
例子:
StringBuilder str = new StringBuilder(); foreach (int item in list.Where(d => d % 2 == 0)) { str.Append(item); }
老式IF用法:
StringBuilder str = new StringBuilder(); foreach (int item in list) { if (item % 2 == 0) { str.Append(item); } }
Take
從數據源開始位置讀取指定的元素個數用。
例子:
var list = Enumerable.Range(1, 100000); foreach (int item in list.Take(10)) { Console.WriteLine(item.ToString()); }
Select
抽取數據源中類型的指定元素組建成新的類型。主要用於簡化數據列或者轉換數據類型,以及獲取元素Index。
例子:
var list = new List<Animal> { new Animal{ Name="hot dog",Sex=1,Age=10}, new Animal{ Name="big dog",Sex=0,Age=11}, new Animal{ Name="bin dog",Sex=0,Age=12}, new Animal{ Name="baby dog",Sex=1,Age=13}, }; foreach (string item in list.Select(a => a.Name)) { Console.WriteLine(item.ToString()); } foreach (var item in list.Select(a => new { Name = a.Name, Length = a.Age * 2, Type = "S" })) { Console.WriteLine(item.ToString()); } foreach (var item in list.Select((value, index) => new { Number = index, Name = value })) { Console.WriteLine(item.ToString()); } foreach (string item in list.Select(a => a.Sex.ToString("D2"))) { Console.WriteLine(item.ToString()); } foreach (int item in list.Select(a => a.Age * 2)) { Console.WriteLine(item.ToString()); }
結果:
SelectMany
將數據源降維抽取,減少For循環。類似Select,適合多重子集的數據源抽取數據。
例子:
var parameters = new Parameter[] { new Parameter() { Name = "正一", Numbers = new int[] { 1, 2, 3 } }, new Parameter() { Name = "清次", Numbers = new int[] { 1, 3, 5 } }, new Parameter() { Name = "誠三", Numbers = new int[] { 2, 4, 6 } }, new Parameter() { Name = "征史", Numbers = new int[] { 9, 8, 7 } }, }; StringBuilder str = new StringBuilder(); var result = parameters.SelectMany(value => value.Numbers); foreach (int value in result) { str.Append($"{value},"); } Console.WriteLine(str.ToString());
結果:
如果使用Select就是如下寫法:
var parameters = new Parameter[] { new Parameter() { Name = "正一", Numbers = new int[] { 1, 2, 3 } }, new Parameter() { Name = "清次", Numbers = new int[] { 1, 3, 5 } }, new Parameter() { Name = "誠三", Numbers = new int[] { 2, 4, 6 } }, new Parameter() { Name = "征史", Numbers = new int[] { 9, 8, 7 } }, }; var results = parameters.Select(value => value.Numbers); StringBuilder str = new StringBuilder(); foreach (int[] values in results) { foreach (int number in values) { str.Append($"{number},"); } } Console.WriteLine(str.ToString());
結果:
Distinct
去掉重復數據留下一個,一般用於基礎數據類型。如果是類需要指定比較方法。
int[] dataA = new int[] { 0, 1, 3, 3, 2 }; List<float> dataB = new List<float>() { 1.5f, 1.5f, 1.5f, 1.5f }; IEnumerable<int> dataA_D = dataA.Distinct(); IEnumerable<float> dataB_D = dataB.Distinct(); foreach (var d in dataA_D) { Console.WriteLine(d); } foreach (var d in dataB_D) { Console.WriteLine(d); }
Any
用來判斷列表是否為空,速度比Count()快。如果是類,可以指定判斷條件。
int[] numbersA = new int[] { }; int[] numbersB = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; var list = new List<Animal> { new Animal{ Name="hot dog",Sex=1}, new Animal{ Name=null,Sex=0}, new Animal{ Name="bin dog",Sex=0}, new Animal{ Name="baby dog",Sex=1}, }; Console.WriteLine(numbersA.Any()); Console.WriteLine(numbersB.Any()); Console.WriteLine(list.Any(a => a.Name == null));
Join
兩組數據結合。也可以用來根據某個表排序數據。
public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>( this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector );
參數說明:
outer:結合的數據列表A
inner:結合的數據列表B
outerKeySelector:列表A的主鍵字段
innerKeySelector:列表B的主鍵字段
resultSelector:返回結果定義。(匿名類居多)
PersonData[] persons = new PersonData[] { new PersonData() { Name = "正一郎", ItemID = 0 }, new PersonData() { Name = "清次郎", ItemID = 1 }, new PersonData() { Name = "誠三郎", ItemID = 2 }, new PersonData() { Name = "征史郎", ItemID = 0 }, }; ItemData[] items = new ItemData[] { new ItemData() { ID = 0, Name = "金" }, new ItemData() { ID = 1, Name = "権力" }, }; var joinList = persons.Join( items, person => person.ItemID, item => item.ID, (person, item) => new { PersonName = person.Name, ItemName = item.Name }); foreach (var item in joinList) { Console.WriteLine($"Person:{item.PersonName}, Item:{item.ItemName}"); }
Except
求兩個數據列表的差分集合用。
int[] numbersA = new int[] { 1, 2, 3, 4, 5 }; int[] numbersB = new int[] { 8, 6, 4, 2, 0 }; IEnumerable<int> results = numbersA.Except(numbersB); foreach (var d in results) { Console.WriteLine(d); }
自定義比較條件的情況
class Parameter { public int ID { get; set; } public string Name { get; set; } public override string ToString() { return string.Format("ID:{0}, Name:{1}", ID, Name); } } class ParameterComparer : IEqualityComparer<Parameter> { public bool Equals(Parameter i_lhs, Parameter i_rhs) { if (i_lhs.ID == i_rhs.ID && i_lhs.Name == i_rhs.Name) { return true; } return false; } public int GetHashCode(Parameter i_obj) { return i_obj.ID ^ i_obj.Name.GetHashCode(); } } class Program { static void Main(string[] args) { Parameter[] dataA = new Parameter[] { new Parameter() { ID = 0, Name = "正一郎" }, new Parameter() { ID = 5, Name = "清次郎" }, new Parameter() { ID = 3, Name = "誠三郎" }, new Parameter() { ID = 9, Name = "征史郎" }, }; Parameter[] dataB = new Parameter[] { new Parameter() { ID = 5, Name = "清次郎" }, new Parameter() { ID = 3, Name = "誠三郎" }, new Parameter() { ID = 2, Name = "征史郎" }, }; ParameterComparer compare = new ParameterComparer(); IEnumerable<Parameter> results = dataA.Except(dataB, compare); foreach (var item in results) { Console.WriteLine(item.ToString()); } Console.ReadKey(); } }
Range
指定開始位置,指定個數的連續列表做成。
IEnumerable<int> intSequenceA = Enumerable.Range(1, 5); IEnumerable<int> intSequenceB = Enumerable.Range(-1, 3); IEnumerable<int> intSequenceC = Enumerable.Range(100, 4); foreach (var d in intSequenceA) { Console.WriteLine(d); } Console.WriteLine("========="); foreach (var d in intSequenceB) { Console.WriteLine(d); } Console.WriteLine("========="); foreach (var d in intSequenceC) { Console.WriteLine(d); }
備注:https://www.urablog.xyz/entry/2018/07/10/070000