LINQ学习总结
- 获取数据源
- 创建查询
- 方法语法
- 标准查询运算符
- Cast
- GroupBy
- GroupJoin
- Join
- OrderBy
- OrderByDescending
- ThenBy
- ThenByDescending
- Select
- SelectMany
- Where
- Aggregate
- All 是否都满足条件
- Any 是否包含
- Average 平均值
- Concat 组合
- Except 差集
- Intersect 交集
- Union 并集
- Contains 是否包含
- Count 数量
- Distinct 去重
- ElementAt
- ElementAtOrDefault
- Empty 指定类型空值
- First 第一个
- FirstOrDefault
- Last 最后一个
- LastOrDefault
- Max
- Min
- OfType 指定类型筛选元素
- Range
- Repeat
- SequanceEqual 是否引用同一对象
- Single 单个特定元素
- SingleOrDefault
- Sum
- Reverse 反转
- Skip
- SkipWhile
- Take
- TakeWhile
- ToArray
- ToList
- ToDictionary
- ToLookup
- 执行方式
获取数据源
语句:from 范围变量 in 数据源
可查询类型(支持IEnumberable或派生接口,如泛型IQueryable 的类型)无需修改或处理就可作为LINQ数据源。
如果源数据不是可查询类型,则LINQ提供程序必须以此方式表示源数据,如下操作。
//LINQ to XML 将 XML 文档加载到可查询的 XElement 类型中
XElement contacts = XElement.Load(@"c:\myContactList.xml");
//LINQ to SQL
Northwnd db = new Northwnd(@"c:\northwnd.mdf");
IQueryable<Customer> custQuery =
from cust in db.Customers
where cust.City == "London"
select cust;
可以通过使用let子句引入其他范围变量
在一般情况下,编译器可以直接推断范围变量的类型,而若数据源是非泛型IEnumerable集合,必须显式声明范围变量的类型,如下操作。
//arrayList为非泛型的ArrayList集合
var query=from Student s in arrayList;
创建查询
from子句
from子句
var lowNums = from num in numbers
where num < 5
select num;
复合from子句
var scoreQuery = from student in students
from score in student.Scores
where score > 90
select new { Last = student.LastName, score };
筛选(where子句)
使用where子句,仅返回表达式为true的元素。可以使用“&&”和“||”应用更多的筛选器表达式。
var queryLondonCustomers = from cust in customers
where cust.City == "London" && cust.Name == "Devon"
select cust;
orderby子句
对返回的数据排序,ascending为顺序,descending为逆序,默认为顺序
class OrderbySample1
{
static void Main()
{
// Create a delicious data source.
string[] fruits = { "cherry", "apple", "blueberry" };
// 顺序排序.
IEnumerable<string> sortAscendingQuery =
from fruit in fruits
orderby fruit //"ascending" is default
select fruit;
}
}
/* Output:
Ascending:
apple
blueberry
cherry
group by子句
语句:group item by key
根据指定的键分组
var queryCustomersByCity =
from cust in customers
group cust by cust.City;
foreach (var customerGroup in queryCustomersByCity)
{
Console.WriteLine(customerGroup.Key);
foreach (Customer customer in customerGroup)
{
Console.WriteLine(" {0}", customer.Name);
}
}
如上操作的结果为列表形式,列表元素带有Key,所有元素根据key来分组。
语句:group item by key into group
使用into可以得到范围变量,能直接引用某个组操作
// custQuery is an IEnumerable<IGrouping<string, Customer>>
var custQuery =
from cust in customers
group cust by cust.City into custGroup
where custGroup.Count() > 2
orderby custGroup.Key
select custGroup;
join子句
语句:join item in itemResource on item.property equals preItem.property
在 LINQ 中,join 子句始终作用于对象集合,而非直接作用于数据库表。
//查找所有位置相同的客户和分销商
var innerJoinQuery =
from cust in customers
join dist in distributors on cust.City equals dist.City
select new { CustomerName = cust.Name, DistributorName = dist.Name };
select子句
查询表达式必须以 select 子句或 group 子句结尾。 在最简单的情况下,select 子句仅指定范围变量, 这时返回的序列包含与数据源类型相同的元素。此外,select 子句还提供了强大的机制,用于将源数据转换(或投影)为新类型。
var query = from cust in Customer
select new {Name = cust.Name, City = cust.City};
方法语法
上述的方法皆属于查询语法。查询语法和方法语法在语义上是相同的,但是查询语法更简单且更易于阅读。 某些查询必须表示为方法调用(比如.Count()的查询)。
//查询语法:
IEnumerable<int> numQuery1 =
from num in numbers
where num % 2 == 0
orderby num
select num;
//方法语法:
IEnumerable<int> numQuery2 = numbers.Where(num => num % 2 == 0).OrderBy(n => n);
标准查询运算符
Cast
执行方式:流式处理
将 IEnumerable 的元素强制转换为指定的类型。
IEnumerable<string> query =
fruits.Cast<string>().OrderBy(fruit => fruit).Select(fruit => fruit);
GroupBy
执行方式:非流式处理
根据指定的键选择器函数对序列中的元素进行分组,并且从每个组及其键中创建结果值。 通过使用指定的函数对每个组的元素进行投影。
public static void GroupByEx4()
{
// Create a list of pets.
List<Pet> petsList =
new List<Pet>{ new Pet { Name="Barley", Age=8.3 },
new Pet { Name="Boots", Age=4.9 },
new Pet { Name="Whiskers", Age=1.5 },
new Pet { Name="Daisy", Age=4.3 } };
var query = petsList.GroupBy(
pet => Math.Floor(pet.Age), //key
pet => pet.Age, //element
(baseAge, ages) => new
{
Key = baseAge,
Count = ages.Count(),
Min = ages.Min(),
Max = ages.Max()
}); //结果集(key,IEnumerable<T> groupList)
// Iterate over each anonymous type.
foreach (var result in query)
{
Console.WriteLine("\nAge group: " + result.Key);
Console.WriteLine("Number of pets in this age group: " + result.Count);
Console.WriteLine("Minimum age: " + result.Min);
Console.WriteLine("Maximum age: " + result.Max);
}
/* This code produces the following output:
Age group: 8
Number of pets in this age group: 1
Minimum age: 8.3
Maximum age: 8.3
Age group: 4
Number of pets in this age group: 2
Minimum age: 4.3
Maximum age: 4.9
Age group: 1
Number of pets in this age group: 1
Minimum age: 1.5
Maximum age: 1.5
*/
GroupJoin
执行方式:流式处理和非流式处理
基于键值等同性对两个序列的元素进行关联,并对结果进行分组。 使用指定的 IEqualityComparer 对键进行比较。
Person magnus = new Person { Name = "Hedlund, Magnus" };
Person terry = new Person { Name = "Adams, Terry" };
Person charlotte = new Person { Name = "Weiss, Charlotte" };
Pet barley = new Pet { Name = "Barley", Owner = terry };
Pet boots = new Pet { Name = "Boots", Owner = terry };
Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte };
Pet daisy = new Pet { Name = "Daisy", Owner = magnus };
List<Person> people = new List<Person> { magnus, terry, charlotte };
List<Pet> pets = new List<Pet> { barley, boots, whiskers, daisy };
var query = //返回IEnumerable<result>
people.GroupJoin(pets, //要联接的序列
person => person, //第一个序列中提取联接键,按键分组
pet => pet.Owner, //第二个序列中提取联接键
(person, petCollection) => //创建结果元素
new
{
OwnerName = person.Name,
Pets = petCollection.Select(pet => pet.Name)
});
Join
执行方式:流式处理与非流式处理
基于匹配键对两个序列的元素进行关联。
var query =
people.Join(pets, //要联接的序列
person => person, //第一个序列中提取联接键
pet => pet.Owner, //第二个序列中提取联接键
(person, pet) => //创建结果元素
new { OwnerName = person.Name, Pet = pet.Name });
OrderBy
执行方式:非流式处理
根据键按升序对序列的元素进行排序。
IEnumerable<Pet> query = pets.OrderBy(pet => pet.Age);
OrderByDescending
执行方式:非流式处理
根据键按降序对序列的元素进行排序。
IEnumerable<Pet> query = pets.OrderByDescending(pet => pet.Age);
ThenBy
执行方式:非流式处理
根据某个键按升序对序列中的元素执行后续排序。
IEnumerable<string> query =
fruits.OrderBy(fruit => fruit.Length).ThenBy(fruit => fruit);
ThenByDescending
执行方式:非流式处理
根据某个键按降序对序列中的元素执行后续排序。
IEnumerable<string> query =
fruits
.OrderBy(fruit => fruit.Length)
.ThenByDescending(fruit => fruit, new CaseInsensitiveComparer());
Select
执行方式:流式处理
通过合并元素的索引,将序列的每个元素投影到新窗体中。
var query =
fruits.Select((fruit, index) =>
new { index, str = fruit.Substring(0, index) });
SelectMany
执行方式:流式处理
将序列的每个元素投影到 IEnumerable,并将结果序列合并为一个序列,并对其中每个元素调用结果选择器函数。
var query =
petOwners
.SelectMany(petOwner => petOwner.Pets, (petOwner, petName) => new { petOwner, petName })
.Where(ownerAndPet => ownerAndPet.petName.StartsWith("S"))
.Select(ownerAndPet =>
new
{
Owner = ownerAndPet.petOwner.Name,
Pet = ownerAndPet.petName
}
);
Where
执行方式:流式处理
根据条件筛值
IEnumerable<string> query = fruits.Where(fruit => fruit.Length < 6);
Aggregate
执行方式:立即执行
将指定的种子值用作累加器的初始值,并使用指定的函数选择结果值。
string[] fruits = { "apple", "mango", "orange", "passionfruit", "grape" };
// Determine whether any string in the array is longer than "banana".
string longestName =
fruits.Aggregate("banana", //种子
(longest, next) => //Func
next.Length > longest.Length ? next : longest,
// Return the final result as an upper case string.
fruit => fruit.ToUpper()); //结果
// This code produces the following output:
//
// The fruit with the longest name is PASSIONFRUIT.
All 是否都满足条件
执行方式:立即执行
确定序列中的所有元素是否都满足条件。
class Pet
{
public string Name { get; set; }
public int Age { get; set; }
}
public static void AllEx()
{
// Create an array of Pets.
Pet[] pets = { new Pet { Name="Barley", Age=10 },
new Pet { Name="Boots", Age=4 },
new Pet { Name="Whiskers", Age=6 } };
// Determine whether all pet names
// in the array start with 'B'.
bool allStartWithB = pets.All(pet =>
pet.Name.StartsWith("B"));
Console.WriteLine(
"{0} pet names start with 'B'.",
allStartWithB ? "All" : "Not all");
}
// This code produces the following output:
//
// Not all pet names start with 'B'.
Any 是否包含
执行方式:立即执行
确定序列中是否包含元素或存在元素满足指定条件。
//判断序列是否包含任何元素
List<int> numbers = new List<int> { 1, 2 };
bool hasElements = numbers.Any();
Console.WriteLine("The list {0} empty.",
hasElements ? "is not" : "is");
// This code produces the following output:
//
// The list is not empty.
bool unvaccinated =//判断是否有元素满足以下条件
pets.Any(p => p.Age > 1 && p.Vaccinated == false);
Average 平均值
执行方式:立即执行
计算数值序列的平均值。
string[] fruits = { "apple", "banana", "mango", "orange", "passionfruit", "grape" };
double average = fruits.Average(s => s.Length);
Console.WriteLine("The average string length is {0}.", average);
Concat 组合
执行方式:流式处理
组合多个输入。
var peopleInSeattle = (from student in students
where student.City == "Seattle"
select student.Last)
.Concat(from teacher in teachers
where teacher.City == "Seattle"
select teacher.Last);
Except 差集
执行方式:流式处理和非流式处理
生成两个序列的差集。
double[] numbers1 = { 2.0, 2.0, 2.1, 2.2, 2.3, 2.3, 2.4, 2.5 };
double[] numbers2 = { 2.2 };
IEnumerable<double> onlyInFirstSet = numbers1.Except(numbers2);
foreach (double number in onlyInFirstSet)
Console.WriteLine(number);
/*
This code produces the following output:
2
2.1
2.3
2.4
2.5
*/
Intersect 交集
执行方式:流式处理与非流式处理
生成两个序列的交集。
public class Product
{
public string Name { get; set; }
public int Code { get; set; }
}
// Custom comparer for the Product class
class ProductComparer : IEqualityComparer<Product>
{
// Products are equal if their names and product numbers are equal.
public bool Equals(Product x, Product y)
{
//Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y)) return true;
//Check whether any of the compared objects is null.
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
//Check whether the products' properties are equal.
return x.Code == y.Code && x.Name == y.Name;
}
// If Equals() returns true for a pair of objects
// then GetHashCode() must return the same value for these objects.
public int GetHashCode(Product product)
{
//Check whether the object is null
if (Object.ReferenceEquals(product, null)) return 0;
//Get hash code for the Name field if it is not null.
int hashProductName = product.Name == null ? 0 : product.Name.GetHashCode();
//Get hash code for the Code field.
int hashProductCode = product.Code.GetHashCode();
//Calculate the hash code for the product.
return hashProductName ^ hashProductCode;
}
}
Product[] store1 = { new Product { Name = "apple", Code = 9 },
new Product { Name = "orange", Code = 4 } };
Product[] store2 = { new Product { Name = "apple", Code = 9 },
new Product { Name = "lemon", Code = 12 } };
IEnumerable<Product> duplicates =
store1.Intersect(store2, new ProductComparer());
foreach (var product in duplicates)
Console.WriteLine(product.Name + " " + product.Code);
/*
This code produces the following output:
apple 9
*/
Union 并集
执行方式:流式处理
通过使用默认的相等比较器,生成两个序列的并集,返回一个包含两个输入序列中的非重复元素的 IEnumerable。
int[] ints1 = { 5, 3, 9, 7, 5, 9, 3, 7 };
int[] ints2 = { 8, 3, 6, 4, 4, 9, 1, 0 };
IEnumerable<int> union = ints1.Union(ints2);
foreach (int num in union)
{
Console.Write("{0} ", num);
}
/*
This code produces the following output:
5 3 9 7 8 6 4 1 0
*/
如果要比较某种自定义数据类型的对象序列,则必须 IEquatable 在 helper 类中实现泛型接口。 下面的代码示例演示如何在自定义数据类型中实现此接口并重写 GetHashCode 和 Equals 方法。
public class ProductA: IEquatable<ProductA>
{
public string Name { get; set; }
public int Code { get; set; }
public bool Equals(ProductA other)
{
if (other is null)
return false;
return this.Name == other.Name && this.Code == other.Code;
}
public override bool Equals(object obj) => Equals(obj as ProductA);
public override int GetHashCode() => (Name, Code).GetHashCode();
}
ProductA[] store1 = { new ProductA { Name = "apple", Code = 9 },
new ProductA { Name = "orange", Code = 4 } };
ProductA[] store2 = { new ProductA { Name = "apple", Code = 9 },
new ProductA { Name = "lemon", Code = 12 } };
//Get the products from the both arrays
//excluding duplicates.
IEnumerable<ProductA> union =
store1.Union(store2);
foreach (var product in union)
Console.WriteLine(product.Name + " " + product.Code);
/*
This code produces the following output:
apple 9
orange 4
lemon 12
*/
Contains 是否包含
执行方式:立即执行
确定序列是否包含指定的元素。
string[] fruits = { "apple", "banana", "mango", "orange", "passionfruit", "grape" };
string fruit = "mango";
bool hasMango = fruits.Contains(fruit);
Count 数量
执行方式:立即执行
返回序列中的元素数量。
string[] fruits = { "apple", "banana", "mango", "orange", "passionfruit", "grape" };
try
{
int numberOfFruits = fruits.Count();
Console.WriteLine(
"There are {0} fruits in the collection.",
numberOfFruits);
}
catch (OverflowException)
{
Console.WriteLine("The count is too large to store as an Int32.");
Console.WriteLine("Try using the LongCount() method instead.");
}
// This code produces the following output:
//
// There are 6 fruits in the collection.
Distinct 去重
执行方式:流式处理
返回序列中的非重复元素。
List<int> ages = new List<int> { 21, 46, 46, 55, 17, 21, 55, 55 };
IEnumerable<int> distinctAges = ages.Distinct();
Console.WriteLine("Distinct ages:");
foreach (int age in distinctAges)
{
Console.WriteLine(age);
}
/*
This code produces the following output:
Distinct ages:
21
46
55
17
*/
ElementAt
执行方式:立即执行
返回序列中指定索引处的元素。
string[] names =
{ "Hartono, Tommy", "Adams, Terry", "Andersen, Henriette Thaulow",
"Hedlund, Magnus", "Ito, Shu" };
Random random = new Random(DateTime.Now.Millisecond);
string name = names.ElementAt(random.Next(0, names.Length));
Console.WriteLine("The name chosen at random is '{0}'.", name);
/*
This code produces output similar to the following:
The name chosen at random is 'Ito, Shu'.
*/
ElementAtOrDefault
执行方式:立即执行
返回序列中指定索引处的元素;如果索引超出范围,则返回默认值。
string[] names =
{ "Hartono, Tommy", "Adams, Terry", "Andersen, Henriette Thaulow",
"Hedlund, Magnus", "Ito, Shu" };
int index = 20;
string name = names.ElementAtOrDefault(index);
Console.WriteLine(
"The name chosen at index {0} is '{1}'.",
index,
String.IsNullOrEmpty(name) ? "<no name at this index>" : name);
/*
This code produces the following output:
The name chosen at index 20 is '<no name at this index>'.
*/
Empty 指定类型空值
执行方式:立即执行
返回具有指定类型参数的空 IEnumerable。
string[] names1 = { "Hartono, Tommy" };
string[] names2 = { "Adams, Terry", "Andersen, Henriette Thaulow",
"Hedlund, Magnus", "Ito, Shu" };
string[] names3 = { "Solanki, Ajay", "Hoeing, Helge",
"Andersen, Henriette Thaulow",
"Potra, Cristina", "Iallo, Lucio" };
List<string[]> namesList =
new List<string[]> { names1, names2, names3 };
// Only include arrays that have four or more elements
IEnumerable<string> allNames =
namesList.Aggregate(Enumerable.Empty<string>(),
(current, next) => next.Length > 3 ? current.Union(next) : current);
foreach (string name in allNames)
{
Console.WriteLine(name);
}
/*
This code produces the following output:
Adams, Terry
Andersen, Henriette Thaulow
Hedlund, Magnus
Ito, Shu
Solanki, Ajay
Hoeing, Helge
Potra, Cristina
Iallo, Lucio
*/
First 第一个
执行方式:立即执行。
返回序列中的第一个元素。
int[] numbers = { 9, 34, 65, 92, 87, 435, 3, 54,
83, 23, 87, 435, 67, 12, 19 };
int first = numbers.First();
Console.WriteLine(first);
/*
This code produces the following output:
9
*/
FirstOrDefault
执行方式:立即执行。
返回序列中的第一个元素;如果未找到该元素,则返回默认值。
string[] names = { "Hartono, Tommy", "Adams, Terry",
"Andersen, Henriette Thaulow",
"Hedlund, Magnus", "Ito, Shu" };
string firstLongName = names.FirstOrDefault(name => name.Length > 20);
Console.WriteLine("The first long name is '{0}'.", firstLongName);
string firstVeryLongName = names.FirstOrDefault(name => name.Length > 30);
Console.WriteLine(
"There is {0} name longer than 30 characters.",
string.IsNullOrEmpty(firstVeryLongName) ? "not a" : "a");
/*
This code produces the following output:
The first long name is 'Andersen, Henriette Thaulow'.
There is not a name longer than 30 characters.
*/
Last 最后一个
执行方式:立即执行
返回序列的最后一个元素。
int[] numbers = { 9, 34, 65, 92, 87, 435, 3, 54,
83, 23, 87, 67, 12, 19 };
int last = numbers.Last();
Console.WriteLine(last);
/*
This code produces the following output:
19
*/
LastOrDefault
执行方式:立即执行
返回序列中的最后一个元素;如果未找到该元素,则返回默认值。
string[] fruits = { };
string last = fruits.LastOrDefault();
Console.WriteLine(
String.IsNullOrEmpty(last) ? "<string is null or empty>" : last);
/*
This code produces the following output:
<string is null or empty>
*/
Max
执行方式:立即执行
返回值序列中的最大值。
List<long> longs = new List<long> { 4294967296L, 466855135L, 81125L };
long max = longs.Max();
Console.WriteLine("The largest number is {0}.", max);
/*
This code produces the following output:
The largest number is 4294967296.
*/
Min
执行方式:立即执行
返回值序列中的最小值。
int?[] grades = { 78, 92, null, 99, 37, 81 };
int? min = grades.Min();
Console.WriteLine("The lowest grade is {0}.", min);
/*
This code produces the following output:
The lowest grade is 37.
*/
OfType 指定类型筛选元素
执行方式:流式处理
根据指定类型筛选 IEnumerable 的元素。
System.Collections.ArrayList fruits = new System.Collections.ArrayList(4);
fruits.Add("Mango");
fruits.Add("Orange");
fruits.Add("Apple");
fruits.Add(3.0);
fruits.Add("Banana");
// Apply OfType() to the ArrayList.
IEnumerable<string> query1 = fruits.OfType<string>();
Console.WriteLine("Elements of type 'string' are:");
foreach (string fruit in query1)
{
Console.WriteLine(fruit);
}
// The following query shows that the standard query operators such as
// Where() can be applied to the ArrayList type after calling OfType().
IEnumerable<string> query2 =
fruits.OfType<string>().Where(fruit => fruit.ToLower().Contains("n"));
Console.WriteLine("\nThe following strings contain 'n':");
foreach (string fruit in query2)
{
Console.WriteLine(fruit);
}
// This code produces the following output:
//
// Elements of type 'string' are:
// Mango
// Orange
// Apple
// Banana
//
// The following strings contain 'n':
// Mango
// Orange
// Banana
Range
执行方式:流式处理
生成指定范围内的整数的序列。Range (int start, int count)。
start Int32
序列中第一个整数的值。
count Int32
要生成的顺序整数的数目。
IEnumerable<int> squares = Enumerable.Range(1, 10).Select(x => x * x);
foreach (int num in squares)
{
Console.WriteLine(num);
}
/*
This code produces the following output:
1
4
9
16
25
36
49
64
81
100
*/
Repeat
执行方式:流式处理
生成包含一个重复值的序列。
IEnumerable<string> strings =
Enumerable.Repeat("I like programming.", 15);
foreach (String str in strings)
{
Console.WriteLine(str);
}
/*
This code produces the following output:
I like programming.
I like programming.
I like programming.
I like programming.
I like programming.
I like programming.
I like programming.
I like programming.
I like programming.
I like programming.
I like programming.
I like programming.
I like programming.
I like programming.
I like programming.
*/
SequanceEqual 是否引用同一对象
执行方式:立即执行
通过使用相应类型的默认相等比较器对序列的元素进行比较,以确定两个序列是否是对同一个对象的引用。
/相等的例子
class Pet
{
public string Name { get; set; }
public int Age { get; set; }
}
public static void SequenceEqualEx1()
{
Pet pet1 = new Pet { Name = "Turbo", Age = 2 };
Pet pet2 = new Pet { Name = "Peanut", Age = 8 };
// Create two lists of pets.
List<Pet> pets1 = new List<Pet> { pet1, pet2 };
List<Pet> pets2 = new List<Pet> { pet1, pet2 };
bool equal = pets1.SequenceEqual(pets2);
Console.WriteLine(
"The lists {0} equal.",
equal ? "are" : "are not");
}
/*
This code produces the following output:
The lists are equal.
*/
//应用对象不同,但值相同,判断仍为不相等
class Pet
{
public string Name { get; set; }
public int Age { get; set; }
}
public static void SequenceEqualEx2()
{
Pet pet1 = new Pet() { Name = "Turbo", Age = 2 };
Pet pet2 = new Pet() { Name = "Peanut", Age = 8 };
// Create two lists of pets.
List<Pet> pets1 = new List<Pet> { pet1, pet2 };
List<Pet> pets2 =
new List<Pet> { new Pet { Name = "Turbo", Age = 2 },
new Pet { Name = "Peanut", Age = 8 } };
bool equal = pets1.SequenceEqual(pets2);
Console.WriteLine("The lists {0} equal.", equal ? "are" : "are not");
}
/*
This code produces the following output:
The lists are not equal.
*/
Single 单个特定元素
执行方式:立即执行
返回序列中的单个特定元素。如果有多个这样的元素存在,则会引发异常。如果该序列并非恰好包含一个元素,则会引发异常。
string[] fruits = { "apple", "banana", "mango",
"orange", "passionfruit", "grape" };
string fruit1 = fruits.Single(fruit => fruit.Length > 10);
Console.WriteLine(fruit1);
/*
This code produces the following output:
passionfruit
*/
SingleOrDefault
执行方式:立即执行
返回序列中的单个特定元素;如果未找到该元素,则返回默认值。如果该序列为空,则返回默认值;如果该序列包含多个元素,此方法将引发异常。
string[] fruits2 = { };
string fruit2 = fruits2.SingleOrDefault();
Console.WriteLine(
String.IsNullOrEmpty(fruit2) ? "No such string!" : fruit2);
/*
This code produces the following output:
No such string!
*/
Sum
执行方式:立即执行
要计算其总和的可以为 null 的 Single 值序列。
float?[] points = { null, 0, 92.83F, null, 100.0F, 37.46F, 81.1F };
float? sum = points.Sum();
Console.WriteLine("Total points earned: {0}", sum);
/*
This code produces the following output:
Total points earned: 311.39
*/
Reverse 反转
执行方式:非流式处理
char[] apple = { 'a', 'p', 'p', 'l', 'e' };
char[] reversed = apple.Reverse().ToArray();
foreach (char chr in reversed)
{
Console.Write(chr + " ");
}
Console.WriteLine();
/*
This code produces the following output:
e l p p a
*/
Skip
执行方式:流式处理
跳过序列中指定数量的元素,然后返回剩余的元素。
int[] grades = { 59, 82, 70, 56, 92, 98, 85 };
IEnumerable<int> lowerGrades =
grades.OrderByDescending(g => g).Skip(3);
Console.WriteLine("All grades except the top three are:");
foreach (int grade in lowerGrades)
{
Console.WriteLine(grade);
}
/*
This code produces the following output:
All grades except the top three are:
82
70
59
56
*/
SkipWhile
执行方式:流式处理
如果指定的条件为 true,则跳过序列中的元素,然后返回剩余的元素。
int[] grades = { 59, 82, 70, 56, 92, 98, 85 };
IEnumerable<int> lowerGrades =
grades
.OrderByDescending(grade => grade)
.SkipWhile(grade => grade >= 80);
Console.WriteLine("All grades below 80:");
foreach (int grade in lowerGrades)
{
Console.WriteLine(grade);
}
/*
This code produces the following output:
All grades below 80:
70
59
56
*/
Take
执行方式:流式处理
从序列的开头返回指定数量的相邻元素。
int[] grades = { 59, 82, 70, 56, 92, 98, 85 };
IEnumerable<int> topThreeGrades =
grades.OrderByDescending(grade => grade).Take(3);
Console.WriteLine("The top three grades are:");
foreach (int grade in topThreeGrades)
{
Console.WriteLine(grade);
}
/*
This code produces the following output:
The top three grades are:
98
92
85
*/
TakeWhile
执行方式:流式处理
如果指定的条件为 true,则返回序列中的元素,然后跳过剩余的元素。
string[] fruits = { "apple", "banana", "mango", "orange",
"passionfruit", "grape" };
IEnumerable<string> query =
fruits.TakeWhile(fruit => String.Compare("orange", fruit, true) != 0);
foreach (string fruit in query)
{
Console.WriteLine(fruit);
}
/*
This code produces the following output:
apple
banana
mango
*/
ToArray
执行方式:立即执行
返回一个包含输入序列中的元素的数组。
class Package
{
public string Company { get; set; }
public double Weight { get; set; }
}
public static void ToArrayEx1()
{
List<Package> packages =
new List<Package>
{ new Package { Company = "Coho Vineyard", Weight = 25.2 },
new Package { Company = "Lucerne Publishing", Weight = 18.7 },
new Package { Company = "Wingtip Toys", Weight = 6.0 },
new Package { Company = "Adventure Works", Weight = 33.8 } };
string[] companies = packages.Select(pkg => pkg.Company).ToArray();
foreach (string company in companies)
{
Console.WriteLine(company);
}
}
/*
This code produces the following output:
Coho Vineyard
Lucerne Publishing
Wingtip Toys
Adventure Works
*/
ToList
执行方式:立即执行
返回一个包含输入序列中的元素的 List。
string[] fruits = { "apple", "passionfruit", "banana", "mango",
"orange", "blueberry", "grape", "strawberry" };
List<int> lengths = fruits.Select(fruit => fruit.Length).ToList();
foreach (int length in lengths)
{
Console.WriteLine(length);
}
/*
This code produces the following output:
5
12
6
5
6
9
5
10
*/
ToDictionary
执行方式:立即执行
根据指定的键选择器和元素选择器函数,从 IEnumerable 创建一个 Dictionary<TKey,TValue>。
class Package
{
public string Company { get; set; }
public double Weight { get; set; }
public long TrackingNumber { get; set; }
}
public static void ToDictionaryEx1()
{
List<Package> packages =
new List<Package>
{ new Package { Company = "Coho Vineyard", Weight = 25.2, TrackingNumber = 89453312L },
new Package { Company = "Lucerne Publishing", Weight = 18.7, TrackingNumber = 89112755L },
new Package { Company = "Wingtip Toys", Weight = 6.0, TrackingNumber = 299456122L },
new Package { Company = "Adventure Works", Weight = 33.8, TrackingNumber = 4665518773L } };
// Create a Dictionary of Package objects,
// using TrackingNumber as the key.
Dictionary<long, Package> dictionary =
packages.ToDictionary(p => p.TrackingNumber);
foreach (KeyValuePair<long, Package> kvp in dictionary)
{
Console.WriteLine(
"Key {0}: {1}, {2} pounds",
kvp.Key,
kvp.Value.Company,
kvp.Value.Weight);
}
}
/*
This code produces the following output:
Key 89453312: Coho Vineyard, 25.2 pounds
Key 89112755: Lucerne Publishing, 18.7 pounds
Key 299456122: Wingtip Toys, 6 pounds
Key 4665518773: Adventure Works, 33.8 pounds
*/
ToLookup
执行方式:立即执行
从 IEnumerable 生成一个泛型 Lookup<TKey,TElement>。
class Package
{
public string Company { get; set; }
public double Weight { get; set; }
public long TrackingNumber { get; set; }
}
public static void ToLookupEx1()
{
// Create a list of Packages.
List<Package> packages =
new List<Package>
{ new Package { Company = "Coho Vineyard",
Weight = 25.2, TrackingNumber = 89453312L },
new Package { Company = "Lucerne Publishing",
Weight = 18.7, TrackingNumber = 89112755L },
new Package { Company = "Wingtip Toys",
Weight = 6.0, TrackingNumber = 299456122L },
new Package { Company = "Contoso Pharmaceuticals",
Weight = 9.3, TrackingNumber = 670053128L },
new Package { Company = "Wide World Importers",
Weight = 33.8, TrackingNumber = 4665518773L } };
// Create a Lookup to organize the packages.
// Use the first character of Company as the key value.
// Select Company appended to TrackingNumber
// as the element values of the Lookup.
ILookup<char, string> lookup =
packages
.ToLookup(p => Convert.ToChar(p.Company.Substring(0, 1)),
p => p.Company + " " + p.TrackingNumber);
// Iterate through each IGrouping in the Lookup.
foreach (IGrouping<char, string> packageGroup in lookup)
{
// Print the key value of the IGrouping.
Console.WriteLine(packageGroup.Key);
// Iterate through each value in the
// IGrouping and print its value.
foreach (string str in packageGroup)
Console.WriteLine(" {0}", str);
}
}
/*
This code produces the following output:
C
Coho Vineyard 89453312
Contoso Pharmaceuticals 670053128
L
Lucerne Publishing 89112755
W
Wingtip Toys 299456122
Wide World Importers 4665518773
*/
ToLookup<TSource,TKey,TElement>(IEnumerable, Func<TSource,TKey>, Func<TSource,TElement>, IEqualityComparer)方法返回一个 Lookup<TKey,TElement> ,它是一个将键映射到值集合的一对多字典。 与 Lookup<TKey,TElement> 不同 Dictionary<TKey,TValue> ,后者执行从键到单个值的一对一映射。
执行方式
即时与推迟
即时执行是在代码中声明查询的位置读取数据来执行运算。
推迟执行是不在代码中声明查询的位置,在foreach中对查询的变量枚举的时候才执行运算。
流式与非流式
推迟执行的查询可分为流式处理和非流式处理
流式处理一边读取源元素一边执行运算,不需要读取全部的数据。
非流式处理是先读取所有的源数据再运算。
tips:如果某个运算符被标为流式处理与非流式处理,则表示在运算中涉及两个输入序列,每个序列的计算方式不同。 在此类情况下,参数列表中的第一个序列始终以延迟流式处理方式来执行计算。