LINQ標準查詢運算符執行方式-流式處理

記錄LINQ標準查詢運算符的學習 api

LINQ的延遲執行方式分兩種,一種是流式處理,另外一種是非流式處理。流式處理是指:當獲取到的源元素足夠計算時,就生成結果元素,不必定要獲取所有源元素。app

ToAsEnumerable
ide

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 若是序列爲空,則返回一個具備默認值的單例類集合ui

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 返回元素不重複的元素,可使用默認比較器,也能夠傳個新的this

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 返回序列之間的差值spa

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 兩個序列進行分組聯接code

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 求序列交集blog

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
*/
相關文章
相關標籤/搜索