C# LINQ 基础
1. LINQ 查询语句
所有 LINQ 查询操作都由以下三个不同的操作组成:
1) 获取数据源。
数据源需要支持“可查询类型”。(支持 IEnumerable<T> 或派生接口(如泛型 IQueryable<T>)的类型称为“可查询类型”。)
a. 数组
b. LINQ to XML.
c. LINQ to SQL.
d. 支持非泛型 IEnumerable 接口的类型(如 ArrayList)也可用作 LINQ 数据源
2) 创建查询。
查询表达式
from 字句指定数据源
where 字句应用筛检器
select 字句指定返回的元素的类型
在 LINQ 中,查询变量本身不执行任何操作并且不返回任何数据。它只是存储在以后某个时刻执行查询时为生成结果而必需的信息。
3) 执行查询。
a.延迟执行
查询变量本身只是存储查询命令。实际的查询执行会延迟到在 foreach 语句中循环访问查询变量时发生。此概念称为“延迟执行”
在 foreach 语句中执行查询,而 foreach 要求使用 IEnumerable 或 IEnumerable<T>。
b.强制立即执行
对一系列源元素执行聚合函数的查询必须首先循环访问这些元素。Count、Max、Average 和 First 就属于此类查询。由于查询本身必须使用 foreach 以便返回结果,因此这些查询在执行时不使用显式 foreach 语句。另外还要注意,这些类型的查询返回单个值,而不是 IEnumerable 集合。
下面的查询返回源数组中偶数的计数:
int evenNumCount = evenNumQuery.Count();
若要强制立即执行任意查询并缓存其结果,可以调用 ToList<TSource> 或 ToArray<TSource> 方法
List<int> numQuery2 = (from num in numbers where (num % 2) == 0 select num).ToList(); // or like this: // numQuery3 is still an int[] var numQuery3 = (from num in numbers where (num % 2) == 0 select num).ToArray();
static void Main(string[] args) { // 1. 设定数据源 int[] numbers = new int[] { 0, 1, 2, 3, 4, 5, 6, 7 }; // 2. 设置查询条件. 这里的query的类型是 IEnumerable<int> var query = from num in numbers where (num % 2) == 0 select num; // 3. 执行查询, 获取结果. Console.WriteLine(" Even numbers are: "); foreach (int num in query) { Console.Write(" {0} ", num); } Console.ReadLine(); }
2. LINQ 方法查询。
在表示语言集成查询 (LINQ) 使用 LINQ 性查询语法,文档中的多数查询编写。 但是,在中,当编译代码时,必须将查询语法转换方法需要 .NET 公共语言运行时 (CLR)。 这些方法调用标准查询运算符,的名称类似Where、Select、GroupBy、Join、Max和 Average。 可以调用这些方法直接使用方法语法而不是查询语法
int[] numbers = { 5, 10, 8, 3, 6, 12}; //Query syntax: IEnumerable<int> numQuery1 = from num in numbers where num % 2 == 0 orderby num select num; //Method syntax: 等效于上面的LINQ查询语句。 IEnumerable<int> numQuery2 = numbers.Where(num => num % 2 == 0).OrderBy(n => n);
3. List 与 Linq
很多时候,从一个关系表中挑出一个我们需要的元素列表采用SQL语句是再容易不过的了,其实C#的List中也可以采用类似的方法,虽然List中集成了Select(), Where()等语句,不过如果你的判断规则较为复杂,或者想要看起来一目了然,以下的方法也是可行的:
首先假设你有一个类
public class People { public string Name { get; set; } public int Age { get; set; } }
并且有一些初始化语句
List<People> PeopleList = new List<People>(); PeopleList.Add(new People() { Name = "Haocheng Wu", Age = 24 }); PeopleList.Add(new People() { Name = "Haocheng Wu", Age = 25 }); PeopleList.Add(new People() { Name = "James Wu", Age = 23 });
你就可以采用下面类似于SQL语句的方法进行select
List<string> SubPeopleNameList1 = (from people in PeopleList where people.Name == "Haocheng Wu" && people.Age == 24 select people.Name).ToList<string>();
List<string> SubPeopleNameList2 = PeopleList.Where(people => people.Name == "Haocheng Wu" && people.Age == 24).Select(people => people.Name).ToList();
不过显然第一种方法更加一目了然,尤其是当判断条件相当复杂的时候就更加有用了
4. Array 与 Linq
查询一组数组中其中几个数值的平均值。
double[] brights = new double[] { 0, 1, 2, 999, 4, 5, 6, 7, 8, 9, 10 }; double avg = brights.Where(value => value != 999).Average();
剔除指定位置后,取最小,最大值。
double[] maxBrightnesses = new double[] { 1, 2, 3, 4, 11, 6, 7, 8, 9, 10, }; int indexOfCapsLockLed = 4; double minValueOfKeyPixelMax = maxBrightnesses.Where((value, index) => index != indexOfCapsLockLed).Min(); double maxValueOfKeyPixelMax = maxBrightnesses.Where((value, index) => index != indexOfCapsLockLed).Max();
查询两个数组的交集。
string[] a = new string[] { "A", "B", "C", "C", "B", "D" }; string[] b = new string[] { "a", "B", "c", "C", "b", "d" }; string[] c = new string[] { "a", "b", "c", "c", "b", "d" }; string[] commonAB = a.Intersect(b).ToArray(); string[] commonAC = a.Intersect(c).ToArray(); // The length of commonAC array is 0. Console.WriteLine("{0}", commonAC.Length);
int[] arr = new int[3];
int[] arr2 = new int[3];
// 省略为 arr、arr2 赋值
int[] arr3 = arr.Intersect(arr2).ToArray(); // 交集
int[] arr4 = arr.Except(arr2).ToArray(); // 差集
int[] arr5 = arr.Union(arr2).ToArray(); // 并集(arr5 = arr1 + arr2)
参考:http://msdn.microsoft.com/zh-cn/library/bb397906(v=vs.90).aspx
Distinct()
用 List 的 Distinct()方法来筛选List中的唯一值。不能直接简单的使用Distinct(),其函数是基于默认的GetHashCode()方法的,由于class是引用变量,所以不能直接进行对值的比较。
实现的方法有两种
1. Overwrite list中的class 的 Equial 和 GetHashCode 方法。
2. 自定义Compairer.
Reports = this.GetReports().Distinct(new InfoComparer()).ToArray();
IEqualityComparer<MyClass> { public bool Equals(MyClass objA, MyClass objB) { if (object.ReferenceEquals(objA, objB)) { return true; } if (object.ReferenceEquals(objA, null) || object.ReferenceEquals(objB, null)) { return false; } return objA.member1 == objectB.member2 &&objectA.member2==objectB.member2; } public int GetHashCode(MyClass obj) { if (object.ReferenceEquals(obj, null)) { return 0; } return obj.member1.GetHashCode()^obj.member2.GetHashCode(); }