1、LINQ - 限制操作符(Restriction Operators)
- 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.
- 译文:这个示例使用where查找小于5的数组中的所有元素。它演示了查询的组件,包括过滤小数的where子句。
using System;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var lowNums = from num in numbers
where num < 5
select 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子句检查输入序列中项的属性。
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
List<Product> products = GetTransactionList();
var soldOutProducts = from prod in products
where prod.UnitsInStock == 0
select 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的所有产品
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
List<Product> products = GetProductList();
var expensiveInStockProducts = from prod in products
where prod.UnitsInStock > 0 && prod.UnitPrice > 3.00M
select 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查找华盛顿的所有客户,然后使用结果序列向下钻取他们的订单
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
List<Customer> customers = GetCustomerList();
var waCustomers = from cust in customers
where cust.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子句,该子句返回数字名称短于它们的值
using System;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(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.
- 译文:这个示例使用select生成一个比现有整数数组中的整数高一个的整数序列。它演示了select如何修改输入序列。
using System;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(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返回一个产品列表的名称序列。
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(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生成一个字符串序列,表示整数序列的文本版本。
using System;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(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, TaskWhile and ShipWhile partition an output sequence. You use these to limit the portion of an input sequence transferred to the output sequence.
- 译文:Take、Skip、TaskWhile和Shipwhile方法划分一个输出序列。您可以使用它们来限制传输到输出序列的输入序列的部分。
3.1 任务元素(Task elements)
- This sample uses Task to get only the first 3 elements of the array.
- 译文:这个示例使用Task只获取数组的前3个元素。
using System;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(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 Task partitions)
- This sample uses Task to get the first 3 orders from customers in Washington.
- 这个示例使用Task获取来自华盛顿客户的前3个订单。
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
List<Customer> customers = GetCustomerList();
var first3WAOrders = (
from cust in customers
from order in cust.Orders
where cust.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个元素外的所有元素。
using System;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(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 Take to get all but the first 2 orders from customers in Washington.
- 译文:此示例使用Take获取来自华盛顿客户的除前2个订单外的所有订单
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
List<Customer> customers = GetCustomerList();
var waOrders = from cust in customers
from order in cust.Orders
where cust.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的数字。
using System;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(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 索引 TaskWhile(Indexed TaskWhile)
- 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.
- 译文:这个示例使用Takewhile返回从数组开头开始的元素,直到击中一个小于其在数组中的位置的数字。
using System;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(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整除的元素开始获取数组的元素。
using System;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
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的元素开始获取数组的元素。
using System;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(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
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.
- 这个示例使用EqualAll来查看两个序列是否以相同的顺序在所有元素上匹配。
using System;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
var wordsA = new string[] { "cherry", "apple", "blueberry" };
var wordsB = new string[] { "cherry", "apple", "blueberry" };
bool match = wordsA.SequenceEqual(wordsB);
Console.WriteLine($"The sequences match: {match}");
}
}
}
The sequences match: True
- Change the order of elements in one sequence and try that sample again:
- 译文:改变一个序列中元素的顺序并再次尝试该样本:
var wordsB = new string[] { "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创建一个序列,其中一个接一个地包含每个数组的值。
using System;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(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创建一个序列,该序列包含所有客户和产品的名称,包括任何重复的名称。
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(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.
- 译文:这个示例计算两个整数向量的点积。它使用Zip计算点积,传递给它一个lambda函数,将两个数组逐个元素相乘,并对结果求和。
using System;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
int[] vectorA = { 0, 2, 4, 5, 6 };
int[] vectorB = { 1, 3, 5, 7, 8 };
int dotProduct = vectorA.Zip(vectorB, (a, b) => a * b).Sum();
Console.WriteLine($"Dot product: {dotProduct}");
}
}
}
Dot product: 109
5、LINQ - 投影算子(Projection Operators)
- 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.
- 译文:select关键字或select方法提供了这种功能。这些操作符根据输入序列元素创建输出序列元素。输出元素可以是相同类型,也可以是不同类型。
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.
- 译文:本示例使用复合from子句进行查询,该查询返回来自两个数组的所有数字对,使得来自numbersA的数字小于来自numbersB的数字。
using System;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(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
where a < 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语句中枚举查询之前,查询执行是如何进行的。
using System;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
int i = 0;
var q = from n in numbers
select ++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()等操作符立即执行查询。
using System;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
int i = 0;
var q = (from n in numbers
select ++i)
.ToList();
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.
- 译文:下面的示例显示,由于延迟执行,查询可以在数据更改后再次使用,然后对新数据进行操作。
using System;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var lowNumbers = from n in numbers
where n <= 3
select 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];
}
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