LINQ标准查询运算符执行方式-流式处理
LINQ的延迟执行方式分两种,一种是流式处理,另一种是非流式处理。流式处理是指:当获取到的源元素足够计算时,就生成结果元素,不一定要获取全部源元素。
ToAsEnumerable
namespace ConsoleApp4 { class Program { static void Main(string[] args) { Clump<string> fruitClump = new Clump<string> { "apple", "passionfruit", "banana", "mango", "orange", "blueberry", "grape", "strawberry" }; // 调用 Clump's Where() method with a predicate. IEnumerable<string> query1 = fruitClump.Where(fruit => fruit.Contains("o")); Console.WriteLine("query1 has been created.\n"); // 强迫使用 System.Linq.Enumerable 的 Where() 方法. IEnumerable<string> query2 = fruitClump.AsEnumerable().Where(fruit => fruit.Contains("o")); // Display the output. Console.WriteLine("query2 has been created."); } } class Clump<T> : List<T> { // Custom implementation of Where(). public IEnumerable<T> Where(Func<T, bool> predicate) { Console.WriteLine("In Clump's implementation of Where()."); return Enumerable.Where(this, predicate); } } }
Cast
//ArrayList 继承的是IEnumerable 而非IEnumerable<T> System.Collections.ArrayList fruits = new System.Collections.ArrayList(); fruits.Add("mango"); fruits.Add("apple"); fruits.Add("lemon"); //OrderBy扩展的是IEnumerable<T>。因此通过Cast<T>转为IEnumerable<T> IEnumerable<string> query = fruits.Cast<string>().OrderBy(fruit => fruit).Select(fruit => fruit); foreach (string fruit in query) { Console.WriteLine(fruit); }
Concat 连接序列
Pet[] cats = GetCats(); Pet[] dogs = GetDogs(); IEnumerable<string> query = cats.Select(cat => cat.Name).Concat(dogs.Select(dog => dog.Name)); foreach (string name in query) { Console.WriteLine(name); }
//用另一个select重载试试
IEnumerable<string> query1 =
cats.Select((pet, index) => { if (index == 2) { return pet.Name; } else { return ""; } })
.Concat(dogs.Select(dog=>dog.Name))
DefaultIfEmpty 如果序列为空,则返回一个具有默认值的单例类集合
Pet defaultPet = new Pet { Name = "Default Pet", Age = 0 }; List<Pet> pets1 = new List<Pet>{ new Pet { Name="Barley", Age=8 }, new Pet { Name="Boots", Age=4 }, new Pet { Name="Whiskers", Age=1 } }; foreach (Pet pet in pets1.DefaultIfEmpty(defaultPet)) { Console.WriteLine("Name: {0}", pet.Name); } List<Pet> pets2 = new List<Pet>(); foreach (Pet pet in pets2.DefaultIfEmpty(defaultPet)) { Console.WriteLine("\nName: {0}", pet.Name); }
Distinct 返回元素不重复的元素,可以使用默认比较器,也可以传个新的
Product product1 = new Product { Name = "apple", Code = 9 }; Product[] products = { product1, new Product { Name = "orange", Code = 4 }, product1, new Product { Name = "lemon", Code = 12 } }; //在此处,使用默认比较器 IEnumerable<Product> noduplicates = products.Distinct(); //该不该生产当前结果元素,只需要判断之前的源元素有没有一样的,知道判断到有,就不生成 foreach (var product in noduplicates) Console.WriteLine(product.Name + " " + product.Code);
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);
GroupJoin 两个序列进行分组联接
Person magnus = new Person { Name = "Hedlund, Magnus" }; Person terry = new Person { Name = "Adams, Terry" }; Pet barley = new Pet { Name = "Barley", Owner = terry }; Pet boots = new Pet { Name = "Boots", Owner = terry }; Pet daisy = new Pet { Name = "Daisy", Owner = magnus }; List<Person> people = new List<Person> { magnus, terry }; List<Pet> pets = new List<Pet> { barley, boots, daisy }; //Pet的Owner和Person关联 var query = people.GroupJoin(pets, person => person, pet => pet.Owner, (person, petCollection) => new { OwnerName = person.Name, Pets = petCollection.Select(pet => pet.Name) }); foreach (var obj in query) { Console.WriteLine("{0}:", obj.OwnerName); foreach (string pet in obj.Pets) { Console.WriteLine(" {0}", pet); } }
Intersect 求序列交集
Product product = new Product { Name = "apple", Code = 5 }; Product[] store1 = { product, new Product { Name = "orange", Code = 4 } }; Product[] store2 = { product, new Product { Name = "lemon", Code = 12 } }; //在这里 使用默认比较器求差值 var products = store1.Intersect(store2); foreach(var item in products) { Console.WriteLine(item.Name); }
Join基于匹配建对序列的元素进行关联
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 }; //pet的owner和person关联 var query = people.Join(pets, person => person, pet => pet.Owner, (person, pet) => new { OwnerName = person.Name, Pet = pet.Name }); foreach (var obj in query) { Console.WriteLine( "{0} - {1}", obj.OwnerName, obj.Pet); }
OfType 根据指定类型筛选序列指定的元素
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); } Console.WriteLine("Elements of type 'int' are:"); IEnumerable<double> query2 = fruits.OfType<double>(); foreach (var num in query2) { Console.WriteLine(num); }
Range 生成指定范围内的序列
IEnumerable<int> squares = Enumerable.Range(1, 10).Select(x => x * x); foreach (int num in squares) { Console.WriteLine(num); }
Repeat生成一个包含重复值的序列
IEnumerable<string> strings = Enumerable.Repeat("I like programming.", 15); foreach (String str in strings) { Console.WriteLine(str); }
Select 将序列中的每个元素投影到新表单
string[] fruits = { "apple", "banana", "mango", "orange", "passionfruit", "grape" }; var query = fruits.Select((fruit, index) => new { index,str=fruit.Substring(0,index)}); foreach (var obj in query) { Console.WriteLine("{0}", obj); }
SelectMany 将序列的每个元素投影到 IEnumerable<T> ,然后,每个元素投影到的结果序列合并成一个大的序列。
PetOwner[] petOwners = { new PetOwner { Name="Higa", Pets = new List<string>{ "Scruffy", "Sam" } }, new PetOwner { Name="Ashkenazi", Pets = new List<string>{ "Walker", "Sugar" } }, new PetOwner { Name="Price", Pets = new List<string>{ "Scratches", "Diesel" } }, new PetOwner { Name="Hines", Pets = new List<string>{ "Dusty" } } }; //想要的结果,Higa养猪人都有哪些猪,排成一行行的结果。 // {Owner=Higa, Pet=Scruffy} // {Owner=Higa, Pet=Sam} var query = petOwners.Where(owner=>owner.Name=="Higa") .SelectMany(owner => owner.Pets, (owner, pet) => new { owner = owner.Name, pet }); foreach(var obj in query) { Console.WriteLine(obj); }
Skip 跳过指定数量的元素,返回一个剩下元素组成的新序列
int[] grades = { 59, 82, 70, 56, 92, 98, 85 }; IEnumerable<int> lowerGrades = grades.Skip(2); foreach (int grade in lowerGrades) { Console.WriteLine(grade); } //返回结果 //70 //56 //92 //98 //85
SkipWhile 当条件为true,前面的元素忽略,剩下的元素组成一个新序列。
下面有坑,请注意。
int[] grades = { 59, 82, 70, 56, 92, 98, 85 }; IEnumerable<int> newGrades = grades.SkipWhile(grade => grade >= 80); foreach (int grade in newGrades) { Console.WriteLine(grade); } Console.WriteLine("\n"); //排序之后的跳过 IEnumerable<int> lowerGrades = grades.OrderByDescending(g=>g).SkipWhile(grade => grade >= 80); foreach (int grade in lowerGrades) { Console.WriteLine(grade); }
控制台输出结果:
59
82
70
56
92
98
85
70
59
5
Take从序列的开头返回指定数量的相邻元素
int[] grades = { 59, 82, 70, 56, 92, 98, 85 }; IEnumerable<int> newGrades = grades.Take(3); foreach (int grade in newGrades) { Console.WriteLine(grade); }
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); } Console.WriteLine("\n"); IEnumerable<string> query1 = fruits.TakeWhile(fruit => String.Compare("apple", fruit, true) == 0); foreach (string fruit in query1) { Console.WriteLine(fruit); } /* 输出结果: apple banana mango apple */
Union 生成两个序列的并集
跑了好些示例,发现只要通过标准运算符生成的元素如果要通过判断相等操作,都有比较器可以传入的函数。
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); }
Where 基于条件筛选序列,太常用了。
List<string> fruits = new List<string> { "apple", "passionfruit", "banana", "mango", "orange", "blueberry", "grape", "strawberry" }; IEnumerable<string> query = fruits.Where(fruit => fruit.Length < 6); foreach (string fruit in query) { Console.WriteLine(fruit); } /* This code produces the following output: apple mango grape */
量变会引起质变。