The where clause of a LINQ query restricts the output sequence. Only the elements that match a condition are added to the output sequence.
译文:LINQ查询的where子句限制了输出顺序。只有符合条件的元素才会被添加到输出序列中。
1.1 LINQ 查询结构(LINQ query structure)
This sample uses where to find all elements of an array less than 5. It demonstrates the components of a query, including a where clause that filters for small numbers.
usingSystem;//using System.Collections.Generic;usingSystem.Linq;namespaceConsoleApp{classProgram{staticvoidMain(string[] args){int[] numbers ={5,4,1,3,9,8,6,7,2,0};//List<int> numbers = new List<int>(){ 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }var lowNums =from num in numbers
wherenum<5select num;
Console.WriteLine("Numbers < 5");foreach(var x in lowNums){
Console.WriteLine(x);}}}}
Numbers < 5
4
1
3
2
0
1.2 筛选属性上的元素(Filter elements on a property)
This sample uses where to find all products that are out of stock. Its where clause examines a property of the items in the input sequence.
译文:这个示例使用where来查找所有缺货的产品。它的where子句检查输入序列中项的属性。
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;namespaceConsoleApp{classProgram{staticvoidMain(string[] args){// 获取对应列表数据List<Product> products =GetTransactionList();var soldOutProducts =from prod in products
whereprod.UnitsInStock ==0select prod;
Console.WriteLine("Sold out products:");foreach(var product in soldOutProducts){
Console.WriteLine($"{product.ProductName} is sold out!");}}}}
1.3 过滤多个属性上的元素(Filter elements on multiple properties)
This sample uses where to find all products that are in stock and cost more than 3.00 per unit.
译文:此示例使用where查找库存中且单价超过3.00的所有产品
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;namespaceConsoleApp{classProgram{staticvoidMain(string[] args){// 获取对应列表数据List<Product> products =GetProductList();var expensiveInStockProducts =from prod in products
whereprod.UnitsInStock >0&& prod.UnitPrice >3.00Mselect prod;
Console.WriteLine("In-stock products that cost more than 3.00:");foreach(var product in soldOutProducts){
Console.WriteLine($"{product.ProductName} is in stock and costs more than 3.00.");}}}}
1.4 检查输出元素的序列属性(Examine a sequence property of output elements)
This sample uses where to find all customers in Washington and then uses the resulting sequence to drill down into their orders.
译文:本示例使用where查找华盛顿的所有客户,然后使用结果序列向下钻取他们的订单
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;namespaceConsoleApp{classProgram{staticvoidMain(string[] args){List<Customer> customers =GetCustomerList();var waCustomers =from cust in customers
wherecust.Region =="WA"select cust;
Console.WriteLine("Customers from Washington and their orders:");foreach(var customer in waCustomers){
Console.WriteLine($"Customer {customer.CustomerID}: {customer.CompanyName}");foreach(var order in customer.Customers){
Console.WriteLine($" Order {order.OrderID}: {order.OrderDate}");}}}}}
1.5 基于位置的过滤元素(Filter elements based on position)
this sample demonstrates an indexed Where clause that returns digits whose name is shorter than their value.
译文:这个示例演示了一个索引的Where子句,该子句返回数字名称短于它们的值
usingSystem;usingSystem.Linq;namespaceConsoleApp{classProgram{staticvoidMain(string[] args){string[] digits ={"zero","one","two","three","four","five","six","seven","eight","nine"};var shortDigits = digits.Where((digit, index)=> digit.Length < index);
Console.WriteLine("Short digits:");foreach(var d in shortDigits){
Console.WriteLine($"The word {d} is shorter than its value.");}}}}
Short digits:
The word five is shorter than its value.
The word six is shorter than its value.
The word seven is shorter than its value.
The word eight is shorter than its value.
The word nine is shorter than its value.
Notice that this final example shows the Where method rather than the where clause. The two forms are equivalent.
译文:注意,最后一个示例显示的是Where方法,而不是Where子句。这两种形式是等价的。
2、LINQ - 生产操作员(Production Operators)
The select clause of a LINQ query projects the output sequence. It transforms each input element into the shape of the output sequence.
译文:LINQ查询的select子句投射输出序列。它将每个输入元素转换成输出序列的形状
2.1 Select子句(Select clause)
This sample uses select to produce a sequence of ints one higher than those in an existing array of ints. It demonstrates how select can modify the input sequence.
usingSystem;usingSystem.Linq;namespaceConsoleApp{classProgram{staticvoidMain(string[] args){int[] numbers ={5,4,1,3,9,8,6,7,2,0};var numsPlusOne =from n in numbers
select n +1;
Console.WriteLine("Numbers + 1:");foreach(int i in numsPlusOne){
Console.WriteLine(i);}}}}
Numbers + 1:
6
5
2
4
10
9
7
8
3
1
2.2 选择单个属性(Select a single property)
This sample uses select to return a sequence of just the names of a list of products.
译文:这个示例使用select返回一个产品列表的名称序列。
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;namespaceConsoleApp{classProgram{staticvoidMain(string[] args){// 获取对应列表数据List<Product> products =GetProductList();var productNames =from p in products
select p.ProductName;
Console.WriteLine("Product Names:");foreach(var productName in productNames){
Console.WriteLine(productName);}}}}
2.3 选择变换(Transform with select)
This sample uses select to produce a sequence of strings representing the text version of a sequence of ints.
译文:这个示例使用select生成一个字符串序列,表示整数序列的文本版本。
usingSystem;usingSystem.Linq;namespaceConsoleApp{classProgram{staticvoidMain(string[] args){int[] numbers ={5,4,1,3,9,8,6,7,2,0};string[] strings ={"zero","one","two","three","four","five","six","seven","eight","nine"};var textNums =from n in numbers
select strings[n];
Console.WriteLine("Number strings:");foreach(var s in textNums){
Console.WriteLine(s);}}}}
Number strings:
five
four
one
three
nine
eight
six
seven
two
zero
3、LINQ - 分区算子(Partition Operators)
The methods Take, Skip, TakeWhile and ShipWhile partition an output sequence. You use these to limit the portion of an input sequence transferred to the output sequence.
This sample uses Take to get only the first 3 elements of the array.
译文:这个示例使用Take只获取数组的前3个元素。
usingSystem;usingSystem.Linq;namespaceConsoleApp{classProgram{staticvoidMain(string[] args){int[] numbers ={5,4,1,3,9,8,6,7,2,0};var first3Numbers = numbers.Take(3);
Console.WriteLine("First 3 numbers:");foreach(int n in first3Numbers){
Console.WriteLine(n);}}}}
First 3 numbers:
5
4
1
3.2 嵌套任务分区(Nested Take partitions)
This sample uses Take to get the first 3 orders from customers in Washington.
这个示例使用Take获取来自华盛顿客户的前3个订单。
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;namespaceConsoleApp{classProgram{staticvoidMain(string[] args){List<Customer> customers =GetCustomerList();var first3WAOrders =(from cust in customers
from order in cust.Orders
wherecust.Region =="WA"select(cust.CustomerID, order.OrderID, order.OrderDate)).Take(3);
Console.WriteLine("First 3 orders in WA:");foreach(var order in first3WAOrders){
Console.WriteLine(order);}}}}
3.3 跳过元素(Skip elements)
This sample uses Skip to get all but the first 4 elements of the array.
译文:这个示例使用Skip获取数组中除前4个元素外的所有元素。
usingSystem;usingSystem.Linq;namespaceConsoleApp{classProgram{staticvoidMain(string[] args){int[] numbers ={5,4,1,3,9,8,6,7,2,0};var allButFirst4Numbers = numbers.Skip(4);
Console.WriteLine("All but first 4 numbers:");foreach(int n in allButFirst4Numbers){
Console.WriteLine(n);}}}}
All but first 4 numbers:
9
8
6
7
2
0
3.4 嵌套跳过分区(Nested skip partitions)
This sample uses Skip to get all but the first 2 orders from customers in Washington.
译文:此示例使用Skip获取来自华盛顿客户的除前2个订单外的所有订单
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;namespaceConsoleApp{classProgram{staticvoidMain(string[] args){List<Customer> customers =GetCustomerList();var waOrders =from cust in customers
from order in cust.Orders
wherecust.Region =="WA"select(cust.CustomerID, order.OrderID, order.OrderDate);var allButFirst2Orders = waOrders.Skip(2);
Console.WriteLine("All but first 2 orders in WA:");foreach(var order in allButFirst2Orders){
Console.WriteLine(order);}}}}
3.5 TakeWhile 语法(TakeWhile syntax)
This sample uses TakeWhile to return elements starting from the beginning of the array until a number is hit that is not less than 6.
译文:这个示例使用Takewhile返回从数组开头开始的元素,直到击中一个不小于6的数字。
usingSystem;usingSystem.Linq;namespaceConsoleApp{classProgram{staticvoidMain(string[] args){int[] numbers ={5,4,1,3,9,8,6,7,2,0};var firstNumberLessThan6 = numbers.TakeWhile(n => n <6);
Console.WriteLine("First numbers less than 6:");foreach(int num in firstNumberLessThan6){
Console.WriteLine(num);}}}}
First numbers less than 6:
5
4
1
3
3.6 索引 TakeWhile(Indexed TakeWhile)
This sample uses TakeWhile to return elements starting from the beginning of the array until a number is hit that is less than its position in the array.
usingSystem;usingSystem.Linq;namespaceConsoleApp{classProgram{staticvoidMain(string[] args){int[] numbers ={5,4,1,3,9,8,6,7,2,0};var firstSmallNumber = numbers.TakeWhile((n, index)=> n >= index);
Console.WriteLine("First numbers not less than their position:");foreach(int n in firstSmallNumber){
Console.WriteLine(n);}}}}
First numbers not less than their position:
5
4
3.7 SkipWhile 语法(SkipWhile syntax)
This sample uses SkipWhile to get the elements of the array starting from the first element divisible by 3.
译文:这个示例使用Skipwhile从第一个能被3整除的元素开始获取数组的元素。
usingSystem;usingSystem.Linq;namespaceConsoleApp{classProgram{staticvoidMain(string[] args){int[] numbers ={5,4,1,3,9,8,6,7,2,0};// In the lambda expression, 'n' is the input parameter that identifies each// element in the collection in succession. It is inferred to be// of type int because numbers is an int array// 译文如下:// 在lambda表达式中,'n'是连续标识集合中的每个元素的输入参数。// 它被推断为int类型,因为numbers是一个int数组var allButFirst3Numbers = numbers.SkipWhile(n => n %3!=0);
Console.WriteLine("All elements starting from first element divisible by 3:");foreach(int n in allButFirst3Numbers){
Console.WriteLine(n);}}}}
All elements starting from first element divisible by 3:
3
9
8
6
7
2
0
3.8 索引 SkipWhile(Indexed SkipWhile)
This sample uses ShipWhile to get the elements of the array starting from the first element less than position.
译文:这个示例使用Shipwhile从第一个小于position的元素开始获取数组的元素。
usingSystem;usingSystem.Linq;namespaceConsoleApp{classProgram{staticvoidMain(string[] args){int[] numbers ={5,4,1,3,9,8,6,7,2,0};var laterNumbers = numbers.SkipWhile((n, index)=> n >= index);
Console.WriteLine("All elements starting from first element less than its position:");foreach(int n in laterNumbers){
Console.WriteLine(n);}}}}
All elements starting from first element less than its position:
1
3
9
8
6
7
2
0
3.9 总结
Take:Take(num),num 填几就取多少个元素,如果取出填超过元素个数,则取出全部
Skip:Skip(num),num 填几就跳过几个元素之后再取,如果填写超过元素个数,则取出为空
TakeWhile:例如 TakeWhile(n => n > 2),从左到右开始判断,到不满足条件的值为止(取前面部分,不包括前面为止的值)
SkipWhile:例如 SkipWhile(n => n > 2),从左到右开始判断,到不满足条件的值为止(取后面部分,包括前面为止的值)
4、LINQ - 序列操作(Sequence Operations)
These operators compare or manipulate entire sequences: EqualAll, Concat, and Combine.
译文:这些操作符比较或操作整个序列:EqualAll、Concat和Combine。
4.1 比较两个序列是否相等(Compare two sequences for equality)
This sample uses EqualAll to see if two sequences match on all elements in the same order.
Change the order of elements in one sequence and try that sample again:
译文:改变一个序列中元素的顺序并再次尝试该样本:
var wordsB =newstring[]{"apple","blueberry","cherry"};
Notice that sequences are equal if they contain the same elements, and those elements are in the same order.
译文:注意,如果序列包含相同的元素,并且这些元素的顺序相同,则它们是相等的。
4.2 连接两个序列(Concatenate two sequences)
This sample uses Concat to create one sequence that contains each array’s values, one after the other.
译文:这个示例使用Concat创建一个序列,其中一个接一个地包含每个数组的值。
usingSystem;usingSystem.Linq;namespaceConsoleApp{classProgram{staticvoidMain(string[] args){int[] numbersA ={0,2,4,5,6,8,9};int[] numbersB ={1,3,5,7,8};var allNumbers = numbersA.Concat(numbersB);
Console.WriteLine("All numbers from both arrays:");foreach(int n in allNumbers){
Console.WriteLine(n);}}}}
All numbers from both arrays:
0
2
4
5
6
8
9
1
3
5
7
8
4.3 连接两个序列的投影(Concatenate projections from two sequences)
This sample uses Concat to create one sequence that contains the names of all customers and products, including any duplicates.
译文:这个示例使用Concat创建一个序列,该序列包含所有客户和产品的名称,包括任何重复的名称。
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;namespaceConsoleApp{classProgram{staticvoidMain(string[] args){List<Customer> customers =GetCustomerList();List<Product> products =GetProductList();var customerNames =from c in customers
select c.CompanyName;var productNames =from p in products
select p.ProductName;var allNames = customerNames.Concat(productNames);
Console.WriteLine("Customer and product names:");foreach(var n in allNames){
Console.WriteLine(n);}}}}
4.4 组合序列与zip(Combine sequences with zip)
This sample calculates the dot product of two integer vectors. It uses Zip to calculate the dot product, passing it a lambda function to multiply two arrays, element by element, and sum the result.
The select keyword or Select method provide this capability. These operators create output sequence elements from input sequence elements. The output elements may be either same or difference types.
5.1 从多个输入序列中选择(Select from multiple input sequences)
This sample uses a compound from clause to make a query that returns all pairs of numbers from both arrays such that the number from numbersA is less than the number from numbersB.
usingSystem;usingSystem.Linq;namespaceConsoleApp{classProgram{staticvoidMain(string[] args){int[] numbersA ={0,2,4,5,6,8,9};int[] numbersB ={1,3,5,7,8};var pairs =from a in numbersA
from b in numbersB
wherea< b
select(a, b);
Console.WriteLine("Pairs where a < b");foreach(var pair in pairs){
Console.WriteLine($"{pair.a} is less than {pair.b}");}}}}
Pairs where a < b
0 is less than 1
0 is less than 3
0 is less than 5
0 is less than 7
0 is less than 8
2 is less than 3
2 is less than 5
2 is less than 7
2 is less than 8
4 is less than 5
4 is less than 7
4 is less than 8
5 is less than 7
5 is less than 8
6 is less than 7
6 is less than 8
6、LINQ - 懒惰而急切的执行(lazy and eager execution)
Learn to specify either eager or lazy query execution
译文:学习指定即时或延迟查询执行
6.1 查询延迟执行(Queries execute lazily)
The following sample shows how query execution is dererred until the query is enumerated at a foreach statement.
译文:下面的示例显示了在foreach语句中枚举查询之前,查询执行是如何进行的。
usingSystem;usingSystem.Linq;namespaceConsoleApp{classProgram{staticvoidMain(string[] args){// Sequence operators form first-class queries that// are not executed until you enumerate over them.// 译文如下:// 序列操作符形成一级查询,在枚举它们之前不会执行这些查询。int[] numbers ={5,4,1,3,9,8,6,7,2,0};int i =0;var q =from n in numbers
select++i;// Note, the local variable 'i' is not incremented// until each element is evaluated (as a side-effect):// 译文如下:// 注意,局部变量'i'直到每个元素都被求值时才递增(作为副作用):foreach(var v in q){
Console.WriteLine($"v = {v}, i = {i}");}foreach(var v in q){
Console.WriteLine($"v = {v}, i = {i}");}}}}
v = 1, i = 1
v = 2, i = 2
v = 3, i = 3
v = 4, i = 4
v = 5, i = 5
v = 6, i = 6
v = 7, i = 7
v = 8, i = 8
v = 9, i = 9
v = 10, i = 10
v = 11, i = 11
v = 12, i = 12
v = 13, i = 13
v = 14, i = 14
v = 15, i = 15
v = 16, i = 16
v = 17, i = 17
v = 18, i = 18
v = 19, i = 19
v = 20, i = 20
6.2 请求即时查询执行(Request eager query execution)
The following sample shows how queries can be executed immediately with operators such as ToList().
译文:下面的示例展示了如何使用ToList()等操作符立即执行查询。
usingSystem;usingSystem.Linq;namespaceConsoleApp{classProgram{staticvoidMain(string[] args){// Methods like ToList() cause the query to be// executed immediately, caching the results.// 译文如下:// 像ToList()这样的方法会立即执行查询,缓存结果。int[] numbers ={5,4,1,3,9,8,6,7,2,0};int i =0;var q =(from n in numbers
select++i).ToList();// The local variable i has already been fully// incremented before we iterate the results:// 译文如下:// 在我们迭代结果之前,局部变量i已经被完全递增了:foreach(var v in q){
Console.WriteLine($"v = {v}, i = {i}");}foreach(var v in q){
Console.WriteLine($"v = {v}, i = {i}");}}}}
v = 1, i = 10
v = 2, i = 10
v = 3, i = 10
v = 4, i = 10
v = 5, i = 10
v = 6, i = 10
v = 7, i = 10
v = 8, i = 10
v = 9, i = 10
v = 10, i = 10
v = 1, i = 10
v = 2, i = 10
v = 3, i = 10
v = 4, i = 10
v = 5, i = 10
v = 6, i = 10
v = 7, i = 10
v = 8, i = 10
v = 9, i = 10
v = 10, i = 10
You can replace the ToList call with a ToArray. Try it.
译文:你可以用一个ToArray来代替ToList调用。试一试。
6.3 使用新结果重用查询(Reuse queries with new results)
The following sample shows how, because of deferred execution, queries can be used again after data changes and will then operate on the new data.
译文:下面的示例显示,由于延迟执行,查询可以在数据更改后再次使用,然后对新数据进行操作。
usingSystem;usingSystem.Linq;namespaceConsoleApp{classProgram{staticvoidMain(string[] args){// Deferred execution lets us define a query once// and then reuse it later after data changes.// 译文如下:// 延迟执行允许我们定义一次查询,然后在数据更改后重用它。int[] numbers ={5,4,1,3,9,8,6,7,2,0};var lowNumbers =from n in numbers
wheren<=3select n;
Console.WriteLine("First run numbers <= 3:");foreach(int n in lowNumbers){
Console.WriteLine(n);}for(int i =0; i <10; i++){
numbers[i]=-numbers[i];}// During this second run, the same query object,// lowNumbers, will be iterating over the new state// of numbers[], producing different results:// 译文如下:// 在第二次运行期间,相同的查询对象lowNumbers将迭代numbers[]的新状态,产生不同的结果:
Console.WriteLine("Second run numbers <= 3:");foreach(var n in lowNumbers){
Console.WriteLine(n);}}}}
First run numbers <= 3:
1
3
2
0
Second run numbers <= 3:
-5
-4
-1
-3
-9
-8
-6
-7
-2
0
6.4 延迟执行和即时查询的区别
6.4.1 上面 6.3 如果将延迟查询换成即时查询的写法
usingSystem;usingSystem.Linq;namespaceConsoleApp{classProgram{staticvoidMain(string[] args){int[] numbers ={5,4,1,3,9,8,6,7,2,0};var lowNumbers =(from n in numbers
wheren<=3select n).ToList();
Console.WriteLine("First run numbers <= 3:");foreach(int n in lowNumbers){
Console.WriteLine(n);}for(int i =0; i <10; i++){
numbers[i]=-numbers[i];}
Console.WriteLine("Second run numbers <= 3:");foreach(var n in lowNumbers){
Console.WriteLine(n);}}}}
First run numbers <= 3:
1
3
2
0
Second run numbers <= 3:
1
3
2
0
6.4.2 从控制台输出结果能得知区别
延迟查询只有在进行循环操作的时候才执行查询,且因为是延迟查询的缘故,数据更改后延迟查询还可继续使用
即时查询在最开始 ToList() 之后获取的值就已经算是执行了查询,获取的值相当于是锁死值了,在 6.2 里面控制台输出 i = 10 也能很明显看出来,之后在循环操作不会再执行查询操作