LINQ学习总结

获取数据源

语句: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:如果某个运算符被标为流式处理与非流式处理,则表示在运算中涉及两个输入序列,每个序列的计算方式不同。 在此类情况下,参数列表中的第一个序列始终以延迟流式处理方式来执行计算。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值