码迷,mamicode.com
首页 > 其他好文 > 详细

LINQ Sample

时间:2017-07-08 10:16:25      阅读:294      评论:0      收藏:0      [点我收藏+]

标签:set   next   object   pes   method   make   传递   format   ict   

Sample LINQ Queries:

In this section, you will learn some complex LINQ queries. We will use the following Student and Standard collection for our queries.

Sample Collections:
    
IList<Student> studentList = new List<Student>() { 
    new Student() { StudentID = 1, StudentName = "John", Age = 18, StandardID = 1 } ,
    new Student() { StudentID = 2, StudentName = "Steve",  Age = 21, StandardID = 1 } ,
    new Student() { StudentID = 3, StudentName = "Bill",  Age = 18, StandardID = 2 } ,
    new Student() { StudentID = 4, StudentName = "Ram" , Age = 20, StandardID = 2 } ,
    new Student() { StudentID = 5, StudentName = "Ron" , Age = 21 } 
};

IList<Standard> standardList = new List<Standard>() { 
    new Standard(){ StandardID = 1, StandardName="Standard 1"},
    new Standard(){ StandardID = 2, StandardName="Standard 2"},
    new Standard(){ StandardID = 3, StandardName="Standard 3"}
};


 

Multiple Select and where operator:

Example: Multiple Select and where operator
        
var studentNames = studentList.Where(s => s.Age > 18)
                              .Select(s => s)
                              .Where(st => st.StandardID > 0)
                              .Select(s => s.StudentName);

Output:

Steve 
Ram


Group By:

The following query returns list students group by StandardID:

Example: LINQ GroupBy query - C#
            
var studentsGroupByStandard = from s in studentList
                              group s by s.StandardID into sg
                              orderby sg.Key 
                                    select new { sg.Key, sg };


foreach (var group in studentsGroupByStandard)
{
    Console.WriteLine("StandardID {0}:", group.Key);
    
    group.sg.ToList().ForEach(st => Console.WriteLine(st.StudentName ));
}

Output:

StandardID 0: 
Ron 
StandardID 1: 
John 
Steve 
StandardID 2: 
Bill 
Ram

The output includes Ron who doesn‘t have any StandardID. So Ron falls under StandardID 0.

To remove a student who doesn‘t have a StandardID, use a where operator before the group operator:

Example: LINQ GroupBy query - C#
            
var studentsGroupByStandard = from s in studentList
                              where s.StandardID > 0
                              group s by s.StandardID into sg
                              orderby sg.Key 
                                    select new { sg.Key, sg };

Output:

StandardID 1: 
John 
Steve 
StandardID 2: 
Bill 
Ram



Left outer join:

Use left outer join to display students under each standard. Display the standard name even if there is no student assigned to that standard.

Example: LINQ Left Outer Join - C#
        
var studentsGroup = from stad in standardList
                    join s in studentList
                    on stad.StandardID equals s.StandardID
                        into sg
                        select new { 
                                        StandardName = stad.StandardName, 
                                        Students = sg 
                                    };

foreach (var group in studentsGroup)
{
    Console.WriteLine(group.StandardName);
    
    group.Students.ToList().ForEach(st => Console.WriteLine(st.StudentName));
}

Output:

Standard 1: 
John 
Steve 
Standard 2: 
Bill 
Ram 
Standard 3: 

In the following example of group by query, we sort the group and select only StudentName:

Example: LINQ Left Outer Join - C#
            
var studentsWithStandard = from stad in standardList
                           join s in studentList
                           on stad.StandardID equals s.StandardID
                           into sg
                               from std_grp in sg 
                               orderby stad.StandardName, std_grp.StudentName 
                               select new { 
                                                StudentName = std_grp.StudentName, 
                                                StandardName = stad.StandardName 
                                };


foreach (var group in studentsWithStandard)
{
    Console.WriteLine("{0} is in {1}", group.StudentName, group.StandardName);
}

Output:

John is in Standard 1 
Steve is in Standard 1 
Bill is in Standard 2 
Ram is in Standard 2

 



Sorting:

The following query returns list of students by ascending order of StandardID and Age.

Example: Sorting
        
var sortedStudents = from s in studentList
                        orderby s.StandardID, s.age
                        select new { 
                                StudentName = s.StudentName, 
                                Age = s.age, 
                                StandardID = s.StandardID };

sortedStudents.ToList().ForEach(s => Console.WriteLine("Student Name: {0}, Age: {1}, StandardID: {2}", s.StudentName, s.Age , s.StandardID));

Output:

Student Name: Ron, Age: 21, StandardID: 0 
Student Name: John, Age: 18, StandardID: 1 
Student Name: Steve, Age: 21, StandardID: 1 
Student Name: Bill, Age: 18, StandardID: 2 
Student Name: Ram, Age: 20, StandardID: 2



Inner Join:

Example: LINQ Inner join - C#
            
var studentWithStandard = from s in studentList
                          join stad in standardList
                          on s.StandardID equals stad.StandardID 
                          select new { 
                                  StudentName = s.StudentName, 
                                  StandardName = stad.StandardName 
                              };

studentWithStandard.ToList().ForEach(s => Console.WriteLine("{0} is in {1}", s.StudentName, s.StandardName  ));
            
        
Output:

John is in Standard 1 
Steve is in Standard 1 
Bill is in Standard 2 
Ram is in Standard 2


 

Nested Query:

C#:
              
var nestedQueries = from s in studentList
                    where s.age > 18 && s.StandardID == 
                        (from std in standardList
                        where std.StandardName == "Standard 1"
                        select std.StandardID).FirstOrDefault()
                            select s;

nestedQueries.ToList().ForEach(s => Console.WriteLine(s.StudentName));

Output:

Steve


Joining Operator: Join (like inner Join)

The joining operators joins the two sequences (collections) and produce a result.

Joining OperatorsUsage
Join The Join operator joins two sequences (collections) based on a key and returns a resulted sequence.
GroupJoin The GroupJoin operator joins two sequences based on keys and returns groups of sequences. It is like Left Outer Join of SQL.

Join:

The Join operator operates on two collections, inner collection & outer collection. It returns a new collection that contains elements from both the collections which satisfies specified expression. It is the same as inner join of SQL.

Join in Method Syntax:

The Join extension method has two overloads as shown below.

Join() method overloads:
public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, 
                                                        IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, 
                                                        Func<TInner, TKey> innerKeySelector, 
                                                        Func<TOuter, TInner, TResult> resultSelector);

public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, 
                                                        IEnumerable<TInner> inner, 
                                                        Func<TOuter, TKey> outerKeySelector,
                                                        Func<TInner, TKey> innerKeySelector, 
                                                        Func<TOuter, TInner, TResult> resultSelector,
                                                        IEqualityComparer<TKey> comparer);

As you can see in the first overload method takes five input parameters (except the first ‘this‘ parameter): 1) outer 2) inner 3) outerKeySelector 4) innerKeySelector 5) resultSelector.

Let‘s take a simple example. The following example joins two string collection and return new collection that includes matching strings in both the collection.

Example: Join operator C#

IList<string> strList1 = new List<string>() { 
    "One", 
    "Two", 
    "Three", 
    "Four"
};

IList<string> strList2 = new List<string>() { 
    "One", 
    "Two", 
    "Five", 
    "Six"
};

var innerJoin = strList1.Join(strList2,
                      str1 => str1, 
                      str2 => str2, 
                      (str1, str2) => str1);

One
Two

Now, let‘s understand join metohod using following Student and Standard class where Student class includes StandardID that matches with StandardID of Standard class.

Example Classes

public class Student{ 
    public int StudentID { get; set; }
    public string StudentName { get; set; }
    public int StandardID { get; set; }
}

public class Standard{ 
    public int StandardID { get; set; }
    public string StandardName { get; set; }
}

The following example demonstrates LINQ Join query.

Example: Join Query C#

IList<Student> studentList = new List<Student>() { 
    new Student() { StudentID = 1, StudentName = "John", StandardID =1 },
    new Student() { StudentID = 2, StudentName = "Moin", StandardID =1 },
    new Student() { StudentID = 3, StudentName = "Bill", StandardID =2 },
    new Student() { StudentID = 4, StudentName = "Ram" , StandardID =2 },
    new Student() { StudentID = 5, StudentName = "Ron"  } 
};

IList<Standard> standardList = new List<Standard>() { 
    new Standard(){ StandardID = 1, StandardName="Standard 1"},
    new Standard(){ StandardID = 2, StandardName="Standard 2"},
    new Standard(){ StandardID = 3, StandardName="Standard 3"}
};

var innerJoin = studentList.Join(// outer sequence 
                      standardList,  // inner sequence 
                      student => student.StandardID,    // outerKeySelector
                      standard => standard.StandardID,  // innerKeySelector
                      (student, standard) => new  // result selector
                                    {
                                        StudentName = student.StudentName,
                                        StandardName = standard.StandardName
                                    });

The following image illustrate the parts of Join operator in the above example.

技术分享join operator

In the above example of join query, studentList is outer sequence because query starts from it. First parameter in Join method is used to specify the inner sequence which is standardList in the above example. Second and third parameter of Join method is used to specify a field whose value should be match using lambda expression in order to include element in the result. The key selector for the outer sequence student => student.StandardID indicates that take StandardID field of each elements of studentList should be match with the key of inner sequence standard => standard.StandardID. If value of both the key field is matched then include that element into result.

The last parameter in Join method is an expression to formulate the result. In the above example, result selector includes StudentName and StandardName property of both the sequence.

StandardID Key of both the sequences (collections) must match otherwise the item will not be included in the result. For example, Ron is not associated with any standard so Ron is not included in the result collection. innerJoinResult in the above example would contain following elements after execution:

John - Standard 1
Moin - Standard 1
Bill - Standard 2
Ram - Standard 2 

 

Join in Query Syntax:

Join operator in query syntax works slightly different than method syntax. It requires outer sequence, inner sequence, key selector and result selector. ‘on‘ keyword is used for key selector where left side of ‘equals‘ operator is outerKeySelector and right side of ‘equals‘ is innerKeySelector.

Syntax: Join in query syntax

        from ... in outerSequence
join ... in innerSequence
on outerKey equals innerKey
select ...

The following example of Join operator in query syntax returns a collection of elements from studentList and standardList if their Student.StandardID and Standard.StandardID is match.

Example: Join operator in query syntax C#

IList<Student> studentList = new List<Student>() { 
    new Student() { StudentID = 1, StudentName = "John", Age = 13, StandardID =1 },
    new Student() { StudentID = 2, StudentName = "Moin",  Age = 21, StandardID =1 },
    new Student() { StudentID = 3, StudentName = "Bill",  Age = 18, StandardID =2 },
    new Student() { StudentID = 4, StudentName = "Ram" , Age = 20, StandardID =2 },
    new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 } 
};

IList<Standard> standardList = new List<Standard>() { 
    new Standard(){ StandardID = 1, StandardName="Standard 1"},
    new Standard(){ StandardID = 2, StandardName="Standard 2"},
    new Standard(){ StandardID = 3, StandardName="Standard 3"}
};

var innerJoin = from s in studentList // outer sequence
                      join st in standardList //inner sequence 
                      on s.StandardID equals st.StandardID // key selector 
                      select new { // result selector 
                                    StudentName = s.StudentName, 
                                    StandardName = st.StandardName 
                                };
 
Output:

John - Standard 1
Moin - Standard 1
Bill - Standard 2
Ram - Standard 2

Note :Use the equals operator to match key selector in query syntax. == is not valid.
技术分享

Points to Remember :

  1. Join and GroupJoin are joining operators.
  2. Join is like inner join of SQL. It returns a new collection that contains common elements from two collections whosh keys matches.
  3. Join operates on two sequences inner sequence and outer sequence and produces a result sequence.
  4. Join query syntax: 
    from... in outerSequence
    join... in innerSequence 
    on outerKey equals innerKey
    select ...

Joining Operator: GroupJoin (like Left Outer Join)

We have seen the Join operator in the previous section. The GroupJoin operator performs the same task as Join operator except that GroupJoin returns a result in group based on specified group key. The GroupJoin operator joins two sequences based on key and groups the result by matching key and then returns the collection of grouped result and key.

GroupJoin in Method Syntax:

GroupJoin requires same parameters as Join. GroupJoin has following two overload methods:

Join() method overloads:
public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> resultSelector);

public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> resultSelector, IEqualityComparer<TKey> comparer);

As you can see in the first overload method takes five input parameters (except the first ‘this‘ parameter): 1) outer 2) inner 3) outerKeySelector 4) innerKeySelector 5) resultSelector. Please notice that resultSelector is of Func delegate type that has second input parameter as IEnumerable type for inner sequence.

Now, let‘s understand GroupJoin using following Student and Standard class where Student class includes StandardID that matches with StandardID of Standard class.

Example Classes

public class Student{ 
    public int StudentID { get; set; }
    public string StudentName { get; set; }
    public int StandardID { get; set; }
}

public class Standard{ 
    public int StandardID { get; set; }
    public string StandardName { get; set; }
}

Consider the following GroupJoin query example.

Example: GroupJoin in Method syntax C#

IList<Student> studentList = new List<Student>() { 
    new Student() { StudentID = 1, StudentName = "John", StandardID =1 },
    new Student() { StudentID = 2, StudentName = "Moin", StandardID =1 },
    new Student() { StudentID = 3, StudentName = "Bill", StandardID =2 },
    new Student() { StudentID = 4, StudentName = "Ram",  StandardID =2 },
    new Student() { StudentID = 5, StudentName = "Ron" } 
};

IList<Standard> standardList = new List<Standard>() { 
    new Standard(){ StandardID = 1, StandardName="Standard 1"},
    new Standard(){ StandardID = 2, StandardName="Standard 2"},
    new Standard(){ StandardID = 3, StandardName="Standard 3"}
};

var groupJoin = standardList.GroupJoin(studentList,  //inner sequence
                                std => std.StandardID, //outerKeySelector 
                                s => s.StandardID,     //innerKeySelector
                                (std, studentsGroup) => new // resultSelector 
                                {
                                    Students = studentsGroup,
                                    StandarFulldName = std.StandardName
                                });

foreach (var item in groupJoin)
{ 
    Console.WriteLine(item.StandarFulldName );

    foreach(var stud in item.Students)
        Console.WriteLine(stud.StudentName);
}

Output:

Standard 1: 
John,
Moin,
Standard 2:
Bill,
Ram,
Standard 3:

In the above example of GroupJoin query, standardList is the outer sequence, because the query starts from it. The first parameter in GroupJoin method is to specify the inner sequence, which is studentList in the above example. The second and third parameters of the GroupJoin() method are to specify a field whose value should be matched using lambda expression, in order to include element in the result. The key selector for the outer sequence standard => standard.StandardIDindicates that StandardID field of each elements in standardList should be match with the key of inner sequence studentList student => student.StandardID. If value of both the key field is matched then include that element into grouped collection studentsGroup where key would be StandardID.

The last parameter in Join method is an expression to formulate the result. In the above example, result selector includes grouped collection studentGroup and StandardName.

The following image illustrate that inner sequence grouped into studentsGroup collection for matching StandardID key and that grouped collection can be used to formulate the result.

技术分享Grouping Operator - GroupJoin

Resultset would include an anonymous objects that has the Students and StandardFullName properties. Students property will be a collection of Students whose StandardID matches with Standard.StandardID.

技术分享GroupJoin Result in Debug View

You can access the result using a ‘foreach‘ loop. Each element will have the StandardFullName & Students property, where Students will be a collection.

Example: Access GroupJoin Result in C#

foreach (var item in groupJoinResult)
{ 
    Console.WriteLine(item.StandarFulldName );

    foreach(var stud in item.Students)
        Console.WriteLine(stud.StudentName);
}
 
Output:

Standard 1: 
John,
Moin,
Standard 2:
Bill,
Ram,
Standard 3:

GroupJoin in Query Syntax:

GroupJoin operator in query syntax works slightly different than method syntax. It requires an outer sequence, inner sequence, key selector and result selector. ‘on‘ keyword is used for key selector where the left side of ‘equals‘ operator is the outerKeySelector and the right side of ‘equals‘ is the innerKeySelector. Use the into keyword to create the grouped collection.

Syntax: GroupJoin in Query syntax

        from ... in outerSequence
join ... in innerSequence
on outerKey equals innerKey
into groupedCollection
select ...

The following example demonstrates the GroupJoin in query syntax.

Example: GroupJoin Query Syntax C#

IList<Student> studentList = new List<Student>() { 
    new Student() { StudentID = 1, StudentName = "John", Age = 13, StandardID =1 },
    new Student() { StudentID = 2, StudentName = "Moin",  Age = 21, StandardID =1 },
    new Student() { StudentID = 3, StudentName = "Bill",  Age = 18, StandardID =2 },
    new Student() { StudentID = 4, StudentName = "Ram" , Age = 20, StandardID =2 },
    new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 } 
};

IList<Standard> standardList = new List<Standard>() { 
    new Standard(){ StandardID = 1, StandardName="Standard 1"},
    new Standard(){ StandardID = 2, StandardName="Standard 2"},
    new Standard(){ StandardID = 3, StandardName="Standard 3"}
};

var groupJoin = from std in standardList 
                      join s in studentList 
                      on std.StandardID equals s.StandardID
                          into studentGroup
                      select new { 
                              Students = studentGroup , 
                              StandardName = std.StandardName 
                          };

foreach (var item in groupJoin)
{ 
    Console.WriteLine(item.StandarFulldName );

    foreach(var stud in item.Students)
        Console.WriteLine(stud.StudentName);
}

 
Output:

Standard 1: 
John,
Moin,
Standard 2:
Bill,
Ram,
Standard 3:


Grouping Operators: GroupBy & ToLookup

The grouping operators do the same thing as the GroupBy clause of SQL query. The grouping operators create a group of elements based on the given key. This group is contained in a special type of collection that implements an IGrouping<TKey,TSource> interface where TKey is a key value, on which the group has been formed and TSource is the collection of elements that matches with the grouping key value.

Grouping OperatorsDescription
GroupBy The GroupBy operator returns groups of elements based on some key value. Each group is represented by IGrouping<TKey, TElement> object.
ToLookup ToLookup is the same as GroupBy; the only difference is the execution of GroupBy is deferred whereas ToLookup execution is immediate.

GroupBy:

技术分享A LINQ query can end with a GroupBy or Select clause.

The GroupBy operator returns a group of elements from the given collection based on some key value. Each group is represented by IGrouping<TKey, TElement> object. Also, the GroupBy method has eight overload methods, so you can use appropriate extension method based on your requirement in method syntax.

 

The result of GroupBy operators is a collection of groups. For example, GroupBy returns IEnumerable<IGrouping<TKey,Student>> from the Student collection:

技术分享Return type of GroupBy()

GroupBy in Query Syntax:

The following example creates a groups of students who have same age. Students of the same age will be in the same collection and each grouped collection will have a key and inner collection, where the key will be the age and the inner collection will include students whose age is matched with a key.

Example: GroupBy in Query syntax C#
            
IList<Student> studentList = new List<Student>() { 
        new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
        new Student() { StudentID = 2, StudentName = "Steve",  Age = 21 } ,
        new Student() { StudentID = 3, StudentName = "Bill",  Age = 18 } ,
        new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
        new Student() { StudentID = 5, StudentName = "Abram" , Age = 21 } 
    };

var groupedResult = from s in studentList
                    group s by s.Age;

//iterate each group        
foreach (var ageGroup in groupedResult)
{
    Console.WriteLine("Age Group: {0}", ageGroup .Key); //Each group has a key 
             
    foreach(Student s in ageGroup) // Each group has inner collection
        Console.WriteLine("Student Name: {0}", s.StudentName);
}

Output:

AgeGroup: 18
StudentName: John
StudentName: Bill
AgeGroup: 21
StudentName: Steve
StudentName: Abram
AgeGroup: 20
StudentName: Ram

As you can see in the above example, you can iterate the group using a ‘foreach‘ loop, where each group contains a key and inner collection. The following figure shows the result in debug view.

技术分享Grouped collection with key and inner collection

GroupBy in Method Syntax:

The GroupBy() extension method works the same way in the method syntax. Specify the lambda expression for key selector field name in GroupBy extension method.

Example: GroupBy in method syntax C#

IList<Student> studentList = new List<Student>() { 
        new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
        new Student() { StudentID = 2, StudentName = "Steve",  Age = 21 } ,
        new Student() { StudentID = 3, StudentName = "Bill",  Age = 18 } ,
        new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
        new Student() { StudentID = 5, StudentName = "Abram" , Age = 21 } 
    };

var groupedResult = studentList.GroupBy(s => s.Age);

foreach (var ageGroup in groupedResult)
{
    Console.WriteLine("Age Group: {0}", ageGroup.Key);  //Each group has a key 
             
    foreach(Student s in ageGroup)  //Each group has a inner collection  
        Console.WriteLine("Student Name: {0}", s.StudentName);
}
Output:

AgeGroup: 18
StudentName: John
StudentName: Bill
AgeGroup: 21
StudentName: Steve
StudentName: Abram
AgeGroup: 20
StudentName: Ram

ToLookup

ToLookup is the same as GroupBy; the only difference is GroupBy execution is deferred, whereas ToLookup execution is immediate. Also, ToLookup is only applicable in Method syntax. ToLookup is not supported in the query syntax.

Example: ToLookup in method syntax C#

IList<Student> studentList = new List<Student>() { 
        new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
        new Student() { StudentID = 2, StudentName = "Steve",  Age = 21 } ,
        new Student() { StudentID = 3, StudentName = "Bill",  Age = 18 } ,
        new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
        new Student() { StudentID = 5, StudentName = "Abram" , Age = 21 } 
    };

var lookupResult = studentList.ToLookup(s => s.age);

foreach (var group in lookupResult)
{
    Console.WriteLine("Age Group: {0}", group.Key);  //Each group has a key 
             
    foreach(Student s in group)  //Each group has a inner collection  
        Console.WriteLine("Student Name: {0}", s.StudentName);
}
        
 

 

Quantifier Operators:

The quantifier operators evaluate elements of the sequence on some condition and return a boolean value to indicate that some or all elements satisfy the condition.

OperatorDescription
All Checks if all the elements in a sequence satisfies the specified condition
Any Checks if any of the elements in a sequence satisfies the specified condition
Contain Checks if the sequence contains a specific element

All:

The All operator evalutes each elements in the given collection on a specified condition and returns True if all the elements satisfy a condition.

Example: All operator C#

IList<Student> studentList = new List<Student>() { 
        new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
        new Student() { StudentID = 2, StudentName = "Steve",  Age = 15 } ,
        new Student() { StudentID = 3, StudentName = "Bill",  Age = 25 } ,
        new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
        new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 } 
    };

// checks whether all the students are teenagers    
bool areAllStudentsTeenAger = studentList.All(s => s.Age > 12 && s.Age < 20);

Console.WriteLine(areAllStudentsTeenAger);
Example: All operator VB.Net

Dim areAllStudentsTeenAger = studentList.All(Function(s) s.Age > 12 And s.Age < 20)
        
Output:
false

Any:

Any checks whether any element satisfy given condition or not? In the following example, Any operation is used to check whether any student is teen ager or not.

Example: Any operator C#

bool isAnyStudentTeenAger = studentList.Any(s => s.age > 12 && s.age < 20);

Example: Any operator VB.Net

Dim isAnyStudentTeenAger = studentList.Any(Function(s) s.Age > 12 And s.Age < 20)

Output:
true
Note :Quantifier operators are Not Supported with C# query syntax.

Aggregation Operators: Aggregate

The aggregation operators perform mathematical operations like Average, Aggregate, Count, Max, Min and Sum, on the numeric property of the elements in the collection.

MethodDescription
Aggregate Performs a custom aggregation operation on the values in the collection.
Average calculates the average of the numeric items in the collection.
Count Counts the elements in a collection.
LongCount Counts the elements in a collection.
Max Finds the largest value in the collection.
Min Finds the smallest value in the collection.
Sum Calculates sum of the values in the collection.

Aggregate:

The Aggregate method performs an accumulate operation. Aggregate extension method has the following overload methods:

Aggregate() method overloads:
public static TSource Aggregate<TSource>(this IEnumerable<TSource> source, 
                                         Func<TSource, TSource, TSource> func);

public static TAccumulate Aggregate<TSource, TAccumulate>(this IEnumerable<TSource> source, 
                                         TAccumulate seed, 
                                         Func<TAccumulate, TSource, TAccumulate> func);

public static TResult Aggregate<TSource, TAccumulate, TResult>(this IEnumerable<TSource> source, 
                                         TAccumulate seed, 
                                         Func<TAccumulate, TSource, TAccumulate> func, 
                                         Func<TAccumulate, TResult> resultSelector);

The following example demonstrates Aggregate method that returns comma seperated elements of the string list.

Example: Aggregate operator in method syntax C#

IList<String> strList = new List<String>() { "One", "Two", "Three", "Four", "Five"};

var commaSeperatedString = strList.Aggregate((s1, s2) => s1 + ", " + s2);

Console.WriteLine(commaSeperatedString); 

Output:
One, Two, Three, Four, Five

In the above example, Aggregate extension method returns comma separated strings from strList collection. The following image illustrates the whole aggregate operation performed in the above example.

技术分享Aggregate extension method

As per the above figure, first item of strList "One" will be pass as s1 and rest of the items will be passed as s2. The lambda expression (s1, s2) => s1 + ", " + s2 will be treated like s1 = s1 + ", " + s1 where s1 will be accumulated for each item in the collection. Thus, Aggregate method will return comma separated string.

Example: Aggregate operator in method syntax VB.Net

Dim strList As IList(Of String) = New List(Of String) From {
                                                            "One", 
                                                            "Two", 
                                                            "Three", 
                                                            "Four", 
                                                            "Five"
                                                        }

Dim commaSeparatedString = strList.Aggregate(Function(s1, s2) s1 + ", " + s2)

Aggregate method with seed value:

The second overload method of Aggregate requires first parameter for seed value to accumulate. Second parameter is Func type delegate:
TAccumulate Aggregate<TSource, TAccumulate>(TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func); .

The following example uses string as a seed value in the Aggregate extension method.

Example: Aggregate method with seed value in C#
            
// Student collection
IList<Student> studentList = new List<Student>>() { 
        new Student() { StudentID = 1, StudentName = "John", Age = 13} ,
        new Student() { StudentID = 2, StudentName = "Moin",  Age = 21 } ,
        new Student() { StudentID = 3, StudentName = "Bill",  Age = 18 } ,
        new Student() { StudentID = 4, StudentName = "Ram" , Age = 20} ,
        new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 } 
    };

string commaSeparatedStudentNames = studentList.Aggregate<Student, string>(
                                        "Student Names: ",  // seed value
                                        (str, s) => str += s.StudentName + "," ); 

Console.WriteLine(commaSeparatedStudentNames); 

Example: Aggregate method with seed value in VB.Net
           
// Student collection
Dim studentList = New List(Of Student) From {
        New Student() With {.StudentID = 1, .StudentName = "John", .Age = 13},
        New Student() With {.StudentID = 2, .StudentName = "Moin", .Age = 21},
        New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 18},
        New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
        New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}
    }
 Dim commaSeparatedStudentNames = studentList.Aggregate(Of String)(
               "Student Names: ", 
               Function(str, s) str + s.StudentName + ",")

Console.WriteLine(commaSeparatedStudentNames); 
 
Output:
Student Names: John, Moin, Bill, Ram, Ron,

In the above example, the first parameter of the Aggregate method is the "Student Names: " string that will be accumulated with all student names. The comma in the lambda expression will be passed as a second parameter.

The following example use Aggregate operator to add the age of all the students.

Example: Aggregate method with seed value in C#
            
// Student collection
IList<Student> studentList = new List<Student>>() { 
        new Student() { StudentID = 1, StudentName = "John", Age = 13} ,
        new Student() { StudentID = 2, StudentName = "Moin",  Age = 21 } ,
        new Student() { StudentID = 3, StudentName = "Bill",  Age = 18 } ,
        new Student() { StudentID = 4, StudentName = "Ram" , Age = 20} ,
        new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 } 
    };

int SumOfStudentsAge = studentList.Aggregate<Student, int>(0, 
                                                (totalAge, s) => totalAge += s.Age  ); 

Aggregate method with result selector:

Now, let‘s see third overload method that required the third parameter of the Func delegate expression for result selector, so that you can formulate the result.

Consider the following example.

Example: Aggregate method C#
            
IList<Student> studentList = new List<Student>>() { 
        new Student() { StudentID = 1, StudentName = "John", Age = 13} ,
        new Student() { StudentID = 2, StudentName = "Moin",  Age = 21 } ,
        new Student() { StudentID = 3, StudentName = "Bill",  Age = 18 } ,
        new Student() { StudentID = 4, StudentName = "Ram" , Age = 20} ,
        new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 } 
    };

string commaSeparatedStudentNames = studentList.Aggregate<Student, string,string>(
                                            String.Empty, // seed value
                                            (str, s) => str += s.StudentName + ",", // returns result using seed value, String.Empty goes to lambda expression as str
                                            str => str.Substring(0,str.Length - 1 )); // result selector that removes last comma

Console.WriteLine(commaSeparatedStudentNames); 

In the above example, we have specified a lambda expression str => str.Substring(0,str.Length - 1 ) which will remove the last comma in the string result. Below is the same example in VB.Net.

Example: Aggregate method VB.Net
           
// Student collection
Dim studentList = New List(Of Student) From {
        New Student() With {.StudentID = 1, .StudentName = "John", .Age = 13},
        New Student() With {.StudentID = 2, .StudentName = "Moin", .Age = 21},
        New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 18},
        New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
        New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}
    }

Dim commaSeparatedStudentNames = studentList.Aggregate(Of String, String)(
               String.Empty, 
               Function(str, s) str + s.StudentName + ",", 
               Function(str) str.Substring(0, str.Length - 1)) 

Console.WriteLine(commaSeparatedStudentNames); 

Output:
John, Moin, Bill, Ram, Ron
Note :Aggregate operator is Not Supported with query syntax in C# or VB.Net.

Aggregation Operator: Max

The Max operator returns the largest numeric element from a collection.

The following example demonstrates Max() on primitive collection.

Example: Max method - C#

IList<int> intList = new List<int>() { 10, 21, 30, 45, 50, 87 };

var largest = intList.Max();

Console.WriteLine("Largest Element: {0}", largest);

var largestEvenElements = intList.Max(i => {
			                        if(i%2 == 0)
				                        return i;
			
			                        return 0;
		                        });

Console.WriteLine("Largest Even Element: {0}", largestEvenElements );

Output:
Largest Element: 87
Largest Even Element: 50

The following example demonstrates Max() method on the complex type collection.

Example: Max operator in method syntax C#

IList<Student> studentList = new List<Student>>() { 
        new Student() { StudentID = 1, StudentName = "John", Age = 13} ,
        new Student() { StudentID = 2, StudentName = "Moin",  Age = 21 } ,
        new Student() { StudentID = 3, StudentName = "Bill",  Age = 18 } ,
        new Student() { StudentID = 4, StudentName = "Ram" , Age = 20} ,
        new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 } 
    };

var oldest = studentList.Max(s => s.Age);

Console.WriteLine("Oldest Student Age: {0}", oldest);
       
Example: Max operator in method syntax VB.Net

Dim studentList = New List(Of Student) From {
        New Student() With {.StudentID = 1, .StudentName = "John", .Age = 13},
        New Student() With {.StudentID = 2, .StudentName = "Moin", .Age = 21},
        New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 18},
        New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
        New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}
}

Dim oldest = studentList.Max(Function(s) s.Age)

Console.WriteLine("Oldest Student Age: {0}", oldest)

Output:
Oldest Student Ag: 21

Max returns a result of any data type. The following example shows how you can find a student with the longest name in the collection:

C#: LINQ Max()

public class Student : IComparable<Student> 
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
    public int Age { get; set; }
    public int StandardID { get; set; }

    public int CompareTo(Student other)
    {
        if (this.StudentName.Length >= other.StudentName.Length)
            return 1;

        return 0;
    }
}

class Program
{
    static void Main(string[] args)
    {
        // Student collection
        IList<Student> studentList = new List<Student>>() { 
                new Student() { StudentID = 1, StudentName = "John", Age = 13} ,
                new Student() { StudentID = 2, StudentName = "Moin",  Age = 21 } ,
                new Student() { StudentID = 3, StudentName = "Bill",  Age = 18 } ,
                new Student() { StudentID = 4, StudentName = "Ram" , Age = 20} ,
                new Student() { StudentID = 5, StudentName = "Steve" , Age = 15 } 
            };

        var studentWithLongName = studentList.Max();

        Console.WriteLine("Student ID: {0}, Student Name: {1}", 
                                        .StudentID, studentWithLongName.StudentName)
    }
}
Output:
Student ID: 5, Student Name: Steve
Note :You can use Min extension method/operator the same way as Max.

As per the above example, to find the student with the longest name, you need to implement IComparable<T> interface and compare student names‘ length in CompareTo method. So now, you can use Max() method which will use CompareTo method in order to return appropriate result.


Equality Operator: SequenceEqual

There is only one equality operator: SequenceEqual. The SequenceEqual method checks whether the number of elements, value of each element and order of elements in two collections are equal or not.

If the collection contains elements of primitive data types then it compares the values and number of elements, whereas collection with complex type elements, checks the references of the objects. So, if the objects have the same reference then they considered as equal otherwise they are considered not equal.

The following example demonstrates the SequenceEqual method with the collection of primitive data types.

Example: SequenceEqual in Method Syntax C#

IList<string> strList1 = new List<string>(){"One", "Two", "Three", "Four", "Three"};

IList<string> strList2 = new List<string>(){"One", "Two", "Three", "Four", "Three"};

bool isEqual = strList1.SequenceEqual(strList2); // returns true
Console.WriteLine(isEqual);

Output:

true

If the order of elements are not the same then SequenceEqual() method returns false.

Example: SequenceEqual in Method Syntax C#

IList<string> strList1 = new List<string>(){"One", "Two", "Three", "Four", "Three"};

IList<string> strList2 = new List<string>(){ "Two", "One", "Three", "Four", "Three"};

bool isEqual = strList1.SequenceEqual(strList2); // returns false
Console.WriteLine(isEqual);

Output:

false

The SequenceEqual extension method checks the references of two objects to determine whether two sequences are equal or not. This may give wrong result. Consider following example:

Example: SequenceEqual in C#
    
Student std = new Student() { StudentID = 1, StudentName = "Bill" };

IList<Student> studentList1 = new List<Student>(){ std };

IList<Student> studentList2 = new List<Student>(){ std };
       
bool isEqual = studentList1.SequenceEqual(studentList2); // returns true

Student std1 = new Student() { StudentID = 1, StudentName = "Bill" };
Student std2 = new Student() { StudentID = 1, StudentName = "Bill" };

IList<Student> studentList3 = new List<Student>(){ std1};

IList<Student> studentList4 = new List<Student>(){ std2 };
       
isEqual = studentList3.SequenceEqual(studentList4);// returns false
        

In the above example, studentList1 and studentList2 contains the same student object, std. So studentList1.SequenceEqual(studentList2) returns true. But, stdList1 and stdList2 contains two seperate student object, std1 and std2. So now, stdList1.SequenceEqual(stdList2) will return false even if std1 and std2 contain the same value.

To compare the values of two collection of complex type (reference type or object), you need to implement IEqualityComperar<T> interface as shown below.

Example: IEqualityComparer C#:

class StudentComparer : IEqualityComparer<Student>
{
    public bool Equals(Student x, Student y)
    {
        if (x.StudentID == y.StudentID && x.StudentName.ToLower() == y.StudentName.ToLower())
            return true;

        return false;
    }

    public int GetHashCode(Student obj)
    {
        return obj.GetHashCode();
    }
}

Now, you can use above StudentComparer class in SequenceEqual extension method as a second parameter to compare the values:

Example: Compare object type elements using SequenceEqual C#
    
IList<Student> studentList1 = new List<Student>() { 
        new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
        new Student() { StudentID = 2, StudentName = "Steve",  Age = 15 } ,
        new Student() { StudentID = 3, StudentName = "Bill",  Age = 25 } ,
        new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
        new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 } 
    };

IList<Student> studentList2 = new List<Student>() { 
        new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
        new Student() { StudentID = 2, StudentName = "Steve",  Age = 15 } ,
        new Student() { StudentID = 3, StudentName = "Bill",  Age = 25 } ,
        new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
        new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 } 
    };
// following returns true
bool isEqual = studentList1.SequenceEqual(studentList2, new StudentComparer()); 
    

Concatenation Operator: Concat

The Concat() method appends two sequences of the same type and returns a new sequence (collection).

Example: Concat in C#

IList<string> collection1 = new List<string>() { "One", "Two", "Three" };
IList<string> collection2 = new List<string>() { "Five", "Six"};

var collection3 = collection1.Concat(collection2);

foreach (string str in collection3)
    Console.WriteLine(str);

Output:
One 
Two
Three
Five
Six
Example: Concat in C#

IList<int> collection1 = new List<int>() { 1, 2, 3 };
IList<int> collection2 = new List<int>() { 4, 5, 6 };

var collection3 = collection1.Concat(collection2);

foreach (int i in collection3)
    Console.WriteLine(i);

Output:
1
2
3
4
5
6

Generation Operator: DefaultIfEmpty:

The DefaultIfEmpty() method returns a new collection with the default value if the given collection on which DefaultIfEmpty() is invoked is empty.

Another overload method of DefaultIfEmpty() takes a value parameter that should be replaced with default value.

Consider the following example.

Example: DefaultIfEmpty C#
            
IList<string> emptyList = new List<string>();

var newList1 = emptyList.DefaultIfEmpty(); 
var newList2 = emptyList.DefaultIfEmpty("None"); 

Console.WriteLine("Count: {0}" , newList1.Count());
Console.WriteLine("Value: {0}" , newList1.ElementAt(0));

Console.WriteLine("Count: {0}" , newList2.Count());
Console.WriteLine("Value: {0}" , newList2.ElementAt(0));

Output:
Count: 1 
Value: 
Count: 1 
Value: None

In the above example, emptyList.DefaultIfEmpty() returns a new string collection with one element whose value is null because null is a default value of string. Another method emptyList.DefaultIfEmpty("None") returns a string collection with one element whose value is "None" instead of null.

The following example demonstrates calling DefaultIfEmpty on int collection.

Example: DefaultIfEmpty C#
            
IList<int> emptyList = new List<int>();

var newList1 = emptyList.DefaultIfEmpty(); 
var newList2 = emptyList.DefaultIfEmpty(100);

Console.WriteLine("Count: {0}" , newList1.Count());
Console.WriteLine("Value: {0}" , newList1.ElementAt(0));

Console.WriteLine("Count: {0}" , newList2.Count());
Console.WriteLine("Value: {0}" , newList2.ElementAt(0));

Output:
Count: 1 
Value: 0 
Count: 1 
Value: 100

The following example demonstrates DefaultIfEmpty() method on complex type collection.

Example: DefaultIfEmpty C#:
            
IList<Student> emptyStudentList = new List<Student>();

var newStudentList1 = studentList.DefaultIfEmpty(new Student());
                 
var newStudentList2 = studentList.DefaultIfEmpty(new Student(){ 
                StudentID = 0, 
                StudentName = "" });

Console.WriteLine("Count: {0} ", newStudentList1.Count());
Console.WriteLine("Student ID: {0} ", newStudentList1.ElementAt(0));

Console.WriteLine("Count: {0} ", newStudentList2.Count());
Console.WriteLine("Student ID: {0} ", newStudentList2.ElementAt(0).StudentID);

Output:
Count: 1 
Student ID: 
Count: 1 
Student ID: 0

Generation Operators: Empty, Range, Repeat

LINQ includes generation operators DefaultIfEmpty, Empty, Range & Repeat. The Empty, Range & Repeat methods are not extension methods for IEnumerable or IQueryable but they are simply static methods defined in a static class Enumerable.

MethodDescription
Empty Returns an empty collection
Range Generates collection of IEnumerable<T> type with specified number of elements with sequential values, starting from first element.
Repeat Generates a collection of IEnumerable<T> type with specified number of elements and each element contains same specified value.

Empty:

The Empty() method is not an extension method of IEnumerable or IQueryable like other LINQ methods. It is a static method included in Enumerable static class. So, you can call it the same way as other static methods like Enumerable.Empty<TResult>(). The Empty() method returns an empty collection of a specified type as shown below.

Example: Enumerable.Empty()
            
var emptyCollection1 = Enumerable.Empty<string>();
var emptyCollection2 = Enumerable.Empty<Student>();

Console.WriteLine("Count: {0} ", emptyCollection1.Count());
Console.WriteLine("Type: {0} ", emptyCollection1.GetType().Name );

Console.WriteLine("Count: {0} ",emptyCollection2.Count());
Console.WriteLine("Type: {0} ", emptyCollection2.GetType().Name );

Output:
Type: String[] 
Count: 0 
Type: Student[] 
Count: 0

Range:

The Range() method returns a collection of IEnumerable<T> type with specified number of elements and sequential values starting from the first element.

Example: Enumerable.Range()
            
var intCollection = Enumerable.Range(10, 10);
Console.WriteLine("Total Count: {0} ", intCollection.Count());

for(int i = 0; i < intCollection.Count(); i++)
    Console.WriteLine("Value at index {0} : {1}", i, intCollection.ElementAt(i));

Output:
Total Count: 10 
Value at index 0 : 10
Value at index 1 : 11
Value at index 2 : 12
Value at index 3 : 13
Value at index 4 : 14
Value at index 5 : 15
Value at index 6 : 16
Value at index 7 : 17
Value at index 8 : 18
Value at index 9 : 19

In the above example, Enumerable.Range(10, 10) creates collection with 10 integer elements with the sequential values starting from 10. First parameter specifies the starting value of elements and second parameter specifies the number of elements to create.

Repeat:

The Repeat() method generates a collection of IEnumerable<T> type with specified number of elements and each element contains same specified value.

Example: Repeat
            
var intCollection = Enumerable.Repeat<int>(10, 10);
Console.WriteLine("Total Count: {0} ", intCollection.Count());

for(int i = 0; i < intCollection.Count(); i++)
    Console.WriteLine("Value at index {0} : {1}", i, intCollection.ElementAt(i));

Output:
Total Count: 10 
Value at index 0: 10
Value at index 1: 10
Value at index 2: 10
Value at index 3: 10
Value at index 4: 10
Value at index 5: 10
Value at index 6: 10
Value at index 7: 10
Value at index 8: 10
Value at index 9: 10

In the above example, Enumerable.Repeat<int>(10, 10) creates collection with 100 integer type elements with the repeated value of 10. First parameter specifies the values of all the elements and second parameter specifies the number of elements to create.


Set operator: Distinct

The following table lists all Set operators available in LINQ.

Set OperatorsUsage
Distinct Returns distinct values from a collection.
Except Returns the difference between two sequences, which means the elements of one collection that do not appear in the second collection.
Intersect Returns the intersection of two sequences, which means elements that appear in both the collections.
Union Returns unique elements from two sequences, which means unique elements that appear in either of the two sequences.

The following figure shows how each set operators works on the collections:

技术分享LINQ Set operators

Distinct:

The Distinct extension method returns a new collection of unique elements from the given collection.

Example: Distinct C#
            
IList<string> strList = new List<string>(){ "One", "Two", "Three", "Two", "Three" };

IList<int> intList = new List<int>(){ 1, 2, 3, 2, 4, 4, 3, 5 };

var distinctList1 = strList.Distinct();

foreach(var str in distinctList1)
    Console.WriteLine(str);

var distinctList2 = intList.Distinct();

foreach(var i in distinctList2)
    Console.WriteLine(i);

Output:

One 
Two
Three 




5

The Distinct extension method doesn‘t compare values of complex type objects. You need to implement IEqualityComparer<T> interface in order to compare the values of complex types. In the following example, StudentComparer class implements IEqualityComparer<Student> to compare Student< objects.

Example: Implement IEqualityComparer in C#

public class Student 
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
    public int Age { get; set; }
}

class StudentComparer : IEqualityComparer<Student>
{
    public bool Equals(Student x, Student y)
    {
        if (x.StudentID == y.StudentID 
                && x.StudentName.ToLower() == y.StudentName.ToLower())
            return true;

        return false;
    }

    public int GetHashCode(Student obj)
    {
        return obj.StudentID.GetHashCode();
    }
}

Now, you can pass an object of the above StudentComparer class in the Distinct() method as a parameter to compare the Student objects as shown below.

Example: Distinct in C#
    
IList<Student> studentList = new List<Student>() { 
        new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
        new Student() { StudentID = 2, StudentName = "Steve",  Age = 15 } ,
        new Student() { StudentID = 3, StudentName = "Bill",  Age = 25 } ,
        new Student() { StudentID = 3, StudentName = "Bill",  Age = 25 } ,
        new Student() { StudentID = 3, StudentName = "Bill",  Age = 25 } ,
        new Student() { StudentID = 3, StudentName = "Bill",  Age = 25 } ,
        new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 } 
    };


var distinctStudents = studentList.Distinct(new StudentComparer()); 

foreach(Student std in distinctStudents)
    Console.WriteLine(std.StudentName);
    
Output:

John
Steve
Bill
Ron

Distinct operator in Query Syntax:

The Distinct operator is Not Supported in C# Query syntax. However, you can use Distinct method of query variable or wrap whole query into brackets and then call Distinct().

Use the Distinct keyword in VB.Net query syntax:

Example: Distinct in query syntax VB.Net

Dim strList = New List(Of string) From {"One", "Three", "Two", "Two", "One" }

Dim distinctStr = From s In strList _
                  Select s Distinct

 


Set operator: Except

The Except() method requires two collections. It returns a new collection with elements from the first collection which do not exist in the second collection (parameter collection).

Example: Except in method syntax C#
            
IList<string> strList1 = new List<string>(){"One", "Two", "Three", "Four", "Five" };
IList<string> strList2 = new List<string>(){"Four", "Five", "Six", "Seven", "Eight"};

var result = strList1.Except(strList2);

foreach(string str in result)
        Console.WriteLine(str);

Output:

One 
Two
Three

Except extension method doesn‘t return the correct result for the collection of complex types. You need to implement IEqualityComparer interface in order to get the correct result from Except method.

Implement IEqualityComparer interface for Student class as shown below:

Example: IEqualityComparer with Except method C#

public class Student 
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
    public int Age { get; set; }
}

class StudentComparer : IEqualityComparer<Student>
{
    public bool Equals(Student x, Student y)
    {
        if (x.StudentID == y.StudentID && x.StudentName.ToLower() == y.StudentName.ToLower())
            return true;

        return false;
    }

    public int GetHashCode(Student obj)
    {
        return obj.StudentID.GetHashCode();
    }
}

Now, you can pass above StudentComparer class in Except extension method in order to get the correct result:

Example: Except() with object type C#
    
IList<Student> studentList1 = new List<Student>() { 
        new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
        new Student() { StudentID = 2, StudentName = "Steve",  Age = 15 } ,
        new Student() { StudentID = 3, StudentName = "Bill",  Age = 25 } ,
        new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 } 
    };

IList<Student> studentList2 = new List<Student>() { 
        new Student() { StudentID = 3, StudentName = "Bill",  Age = 25 } ,
        new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 } 
    };

var resultedCol = studentList1.Except(studentList2,new StudentComparer()); 

foreach(Student std in resultedCol)
    Console.WriteLine(std.StudentName);
    
      
Output:

John
Steve

The Except operator is Not Supported in C# & VB.Net Query syntax. However, you can use Distinct method on query variable or wrap whole query into brackets and then call Except().

The following figure shows how each set operators works on the collections:

技术分享LINQ Set operators


Set operator: Intersect

The Intersect extension method requires two collections. It returns a new collection that includes common elements that exists in both the collection. Consider the following example.

Example: Intersect in method syntax C#
            
IList<string> strList1 = new List<string>() { "One", "Two", "Three", "Four", "Five" };
IList<string> strList2 = new List<string>() { "Four", "Five", "Six", "Seven", "Eight"};

var result = strList1.Intersect(strList2);

foreach(string str in result)
        Console.WriteLine(str);

Output:
Four
Five

The Intersect extension method doesn‘t return the correct result for the collection of complex types. You need to implement IEqualityComparer interface in order to get the correct result from Intersect method.

Implement IEqualityComparer interface for Student class as shown below:

Example: Use IEqualityComparer with Intersect in C#

public class Student 
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
    public int Age { get; set; }
}

class StudentComparer : IEqualityComparer<Student>
{
    public bool Equals(Student x, Student y)
    {
        if (x.StudentID == y.StudentID && 
                        x.StudentName.ToLower() == y.StudentName.ToLower())
            return true;

        return false;
    }

    public int GetHashCode(Student obj)
    {
        return obj.StudentID.GetHashCode();
    }
}

Now, you can pass above StudentComparer class in the Intersect extension method in order to get the correct result:

Example: Intersect operator C#
    
IList<Student> studentList1 = new List<Student>() { 
        new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
        new Student() { StudentID = 2, StudentName = "Steve",  Age = 15 } ,
        new Student() { StudentID = 3, StudentName = "Bill",  Age = 25 } ,
        new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 } 
    };

IList<Student> studentList2 = new List<Student>() { 
        new Student() { StudentID = 3, StudentName = "Bill",  Age = 25 } ,
        new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 } 
    };

var resultedCol = studentList1.Intersect(studentList2, new StudentComparer()); 

foreach(Student std in resultedCol)
    Console.WriteLine(std.StudentName);
    

Output:
Bill
Ron

The Intersect operator is Not Supported in C# & VB.Net Query syntax. However, you can use the Intersect method on a query variable or wrap whole query into brackets and then call Intersect().

The following figure shows how each set operators works on the collections:

技术分享

 


 

 

Set operator: Union

The Union extension method requires two collections and returns a new collection that includes distinct elements from both the collections. Consider the following example.

Example: Union() in C#
            
IList<string> strList1 = new List<string>() { "One", "Two", "three", "Four" };
IList<string> strList2 = new List<string>() { "Two", "THREE", "Four", "Five" };

var result = strList1.Union(strList2);

foreach(string str in result)
        Console.WriteLine(str);

Output:

One 
Two 
three 
THREE 
Four 
Five

The Union extension method doesn‘t return the correct result for the collection of complex types. You need to implement IEqualityComparer interface in order to get the correct result from Union method.

Implement IEqualityComparer interface for Student class as below:

Example: Union operator with IEqualityComparer:

public class Student 
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
    public int Age { get; set; }
}

class StudentComparer : IEqualityComparer<Student>
{
    public bool Equals(Student x, Student y)
    {
        if (x.StudentID == y.StudentID && x.StudentName.ToLower() == y.StudentName.ToLower())
            return true;

        return false;
    }

    public int GetHashCode(Student obj)
    {
        return obj.StudentID.GetHashCode();
    }
}

Now, you can pass above StudentComparer class in the Union extension method to get the correct result:

Example: Union operator C#
    
IList<Student> studentList1 = new List<Student>() { 
        new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
        new Student() { StudentID = 2, StudentName = "Steve",  Age = 15 } ,
        new Student() { StudentID = 3, StudentName = "Bill",  Age = 25 } ,
        new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 } 
    };

IList<Student> studentList2 = new List<Student>() { 
        new Student() { StudentID = 3, StudentName = "Bill",  Age = 25 } ,
        new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 } 
    };

var resultedCol = studentList1.Union(studentList2, new StudentComparer()); 

foreach(Student std in resultedCol)
    Console.WriteLine(std.StudentName);
    
Output:

John 
Steve 
Bill
Ron

Query Syntax:

The Union operator is Not Supported in C# & VB.Net Query syntax. However, you can use Union method on query variable or wrap whole query into brackets and then call Union().

The following figure shows how each set operators works on the collections:

技术分享LINQ Set operators


Partitioning Operators: Skip & SkipWhile

Partitioning operators split the sequence (collection) into two parts and return one of the parts.

MethodDescription
Skip Skips elements up to a specified position starting from the first element in a sequence.
SkipWhile Skips elements based on a condition until an element does not satisfy the condition. If the first element itself doesn‘t satisfy the condition, it then skips 0 elements and returns all the elements in the sequence.
Take Takes elements up to a specified position starting from the first element in a sequence.
TakeWhile Returns elements from the first element until an element does not satisfy the condition. If the first element itself doesn‘t satisfy the condition then returns an empty collection.

Skip:

The Skip() method skips the specified number of element starting from first element and returns rest of the elements.

Example: Skip() - C#
            
IList<string> strList = new List<string>(){ "One", "Two", "Three", "Four", "Five" };

var newList = strList.Skip(2);

foreach(var str in newList)
    Console.WriteLine(str);

Output:

Three
Four 
Five

Skip operator in Query Syntax:

The Skip & SkipWhile operator is Not Supported in C# query syntax. However, you can use Skip/SkipWhile method on a query variable or wrap whole query into brackets and then call Skip/SkipWhile.

The following example demonstrates skip operator in query syntax - VB.NET

Example: Skip operator in VB.Net

Dim skipResult = From s In studentList
                 Skip 3
                 Select s
                    

SkipWhile:

As the name suggests, the SkipWhile() extension method in LINQ skip elements in the collection till the specified condition is true. It returns a new collection that includes all the remaining elements once the specified condition becomes false for any element.

The SkipWhile() method has two overload methods. One method accepts the predicate of Func<TSource, bool> type and other overload method accepts the predicate Func<TSource, int, bool> type that pass the index of an element.

In the following example, SkipWhile() method skips all elements till it finds a string whose length is equal or more than 4 characters.

Example: SkipWhile in C#
            
IList<string> strList = new List<string>() { 
                                            "One", 
                                            "Two", 
                                            "Three", 
                                            "Four", 
                                            "Five", 
                                            "Six"  };

var resultList = strList.SkipWhile(s => s.Length < 4);

foreach(string str in resultList)
        Console.WriteLine(str);

Output:

Three 
Four
Five
Six

In the above example, SkipWhile() skips first two elements because their length is less than 3 and finds third element whose length is equal or more than 4. Once it finds any element whose length is equal or more than 4 characters then it will not skip any other elements even if they are less than 4 characters.

Now, consider the following example where SkipWhile() does not skip any elements because the specified condition is false for the first element.

Example: SkipWhile in C#
            
IList<string> strList = new List<string>() { 
                                            "Three", 
                                            "One", 
                                            "Two", 
                                            "Four", 
                                            "Five", 
                                            "Six"  };

var resultList = strList.SkipWhile(s => s.Length < 4);

foreach(string str in resultList)
        Console.WriteLine(str);

Output:

Three 
One 
Two 
Four
Five
Six

The second overload of SkipWhile passes an index of each elements. Consider the following example.

Example: SkipWhile with index in C#
            
IList<string> strList = new List<string>() { 
                                            "One", 
                                            "Two", 
                                            "Three", 
                                            "Four", 
                                            "Five", 
                                            "Six"  };

var result = strList.SkipWhile((s, i) => s.Length > i);

foreach(string str in result)
    Console.WriteLine(str);

Output:

Five
Six

In the above example, the lambda expression includes element and index of an elements as a parameter. It skips all the elements till the length of a string element is greater than it‘s index.

Skip/SkipWhile operator in Query Syntax:

Skip & SkipWhile operator is NOT Supported in C# query syntax. However, you can use Skip/SkipWhile method on a query variable or wrap whole query into brackets and then call Skip/SkipWhile().

Example: SkipWhile method in VB.Net

Dim strList = New List(Of string) From {
                                        "One", 
                                        "Two", 
                                        "Three", 
                                        "Four", 
                                        "Five", 
                                        "Six"  }

Dim skipWhileResult = From s In studentList
                      Skip While s.Length < 4
                      Select s
    
Output:

Three 
Four 
Five 
Six


Partitioning Operators: Take & TakeWhile

Partitioning operators split the sequence (collection) into two parts and returns one of the parts.

MethodDescription
Skip Skips elements up to a specified position starting from the first element in a sequence.
SkipWhile Skips elements based on a condition until an element does not satisfy the condition. If the first element itself doesn‘t satisfy the condition, it then skips 0 elements and returns all the elements in the sequence.
Take Takes elements up to a specified position starting from the first element in a sequence.
TakeWhile Returns elements from the given collection until the specified condition is true. If the first element itself doesn‘t satisfy the condition then returns an empty collection.

Take:

The Take() extension method returns the specified number of elements starting from the first element.

Example: Take() in C#
            
IList<string> strList = new List<string>(){ "One", "Two", "Three", "Four", "Five" };

var newList = strList.Take(2);

foreach(var str in newList)
    Console.WriteLine(str);

Output:
One
Two

Take & TakeWhile operator is Not Supported in C# query syntax. However, you can use Take/TakeWhile method on query variable or wrap whole query into brackets and then call Take/TakeWhile().

Example: Take operator in query syntax VB.Net

Dim takeResult = From s In studentList
                 Take 3
                 Select s

TakeWhile:

The TakeShile() extension method returns elements from the given collection until the specified condition is true. If the first element itself doesn‘t satisfy the condition then returns an empty collection.

The TakeWhile method has two overload methods. One method accepts the predicate of Func<TSource, bool> type and the other overload method accepts the predicate Func<TSource, int, bool> type that passes the index of element.

In the following example, TakeWhile() method returns a new collection that includes all the elements till it finds a string whose length less than 4 characters.

Example: TakeWhile in C#
            
IList<string> strList = new List<string>() { 
                                            "Three", 
                                            "Four", 
                                            "Five", 
                                            "Hundred"  };

var result = strList.TakeWhile(s => s.Length > 4);

foreach(string str in result)
        Console.WriteLine(str);

Output:
Three

In the above example, TakeWhile() includes only first element because second string element does not satisfied the condition.

TakeWhile also passes an index of current element in predicate function. Following example of TakeWhile method takes elements till length of string element is greater than it‘s index

Example: TakeWhile in C#:
            
IList<string> strList = new List<string>() { 
                                            "One", 
                                            "Two", 
                                            "Three", 
                                            "Four", 
                                            "Five", 
                                            "Six"  };

var resultList = strList.TakeWhile((s, i) => s.Length > i);

foreach(string str in resultList)
        Console.WriteLine(str);

Output:
One 
Two 
Three
Four

Conversion Operators:

The Conversion operators in LINQ are useful in converting the type of the elements in a sequence (collection). There are three types of conversion operators: As operators (AsEnumerable and AsQueryable), To operators (ToArray, ToDictionary, ToList and ToLookup), and Casting operators (Cast and OfType).

The following table lists all the conversion operators.

MethodDescription
AsEnumerable Returns the input sequence as IEnumerable<t>
AsQueryable Converts IEnumerable to IQueryable, to simulate a remote query provider
Cast Coverts a non-generic collection to a generic collection (IEnumerable to IEnumerable<T>)
OfType Filters a collection based on a specified type
ToArray Converts a collection to an array
ToDictionary Puts elements into a Dictionary based on key selector function
ToList Converts collection to List
ToLookup Groups elements into an Lookup<TKey,TElement>

AsEnumerable & AsQueryable:

The AsEnumerable and AsQueryable methods cast or convert a source object to IEnumerable<T> or IQueryable<T> respectively.

Consider the following example: (courtesy: Jon Skeet)

Example: AsEnumerable & AsQueryable operator in C#:
        
class Program
{

    static void ReportTypeProperties<T>(T obj)
    {
        Console.WriteLine("Compile-time type: {0}", typeof(T).Name);
        Console.WriteLine("Actual type: {0}", obj.GetType().Name);
    }

    static void Main(string[] args)
    {
        Student[] studentArray = { 
                new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
                new Student() { StudentID = 2, StudentName = "Steve",  Age = 21 } ,
                new Student() { StudentID = 3, StudentName = "Bill",  Age = 25 } ,
                new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
                new Student() { StudentID = 5, StudentName = "Ron" , Age = 31 } ,
            };   
            
        ReportTypeProperties( studentArray);
        ReportTypeProperties(studentArray.AsEnumerable());
        ReportTypeProperties(studentArray.AsQueryable());   
    }
}      
Output:
Compile-time type: Student[] 
Actual type: Student[]
Compile-time type: IEnumerable`1
Actual type: Student[]
Compile-time type: IQueryable`1
Actual type: EnumerableQuery`1

As you can see in the above example AsEnumerable and AsQueryable methods convert compile time type to IEnumerable and IQueryable respectively

Visit stackoverflow for detail information on AsEnumerable and AsQueryable method.

Cast:

Cast does the same thing as AsEnumerable<T>. It cast the source object into IEnumerable<T>.

Example: Cast operator in C#
        
class Program
{

    static void ReportTypeProperties<T>(T obj)
    {
        Console.WriteLine("Compile-time type: {0}", typeof(T).Name);
        Console.WriteLine("Actual type: {0}", obj.GetType().Name);
    }

    static void Main(string[] args)
    {
        Student[] studentArray = { 
                new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
                new Student() { StudentID = 2, StudentName = "Steve",  Age = 21 } ,
                new Student() { StudentID = 3, StudentName = "Bill",  Age = 25 } ,
                new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
                new Student() { StudentID = 5, StudentName = "Ron" , Age = 31 } ,
            };   
         
        ReportTypeProperties( studentArray);
        ReportTypeProperties(studentArray.Cast<Student>());
    }
}      
Output:
Compile-time type: Student[] 
Actual type: Student[]
Compile-time type: IEnumerable`1
Actual type: Student[]
Compile-time type: IEnumerable`1
Actual type: Student[]
Compile-time type: IEnumerable`1
Actual type: Student[]

studentArray.Cast<Student>() is the same as (IEnumerable<Student>)studentArray but Cast<Student>() is more readable.

To Operators: ToArray(), ToList(), ToDictionary():

As the name suggests, ToArray(), ToList(), ToDictionary() method converts a source object into an array, List or Dictionary respectively.

To operators force the execution of the query. It forces the remote query provider to execute a query and get the result from the underlying data source e.g. SQL Server database.

Example: ToArray & ToList in C#
        
IList<string> strList = new List<string>() { 
                                            "One", 
                                            "Two", 
                                            "Three", 
                                            "Four", 
                                            "Three" 
                                            };

string[] strArray = strList.ToArray<string>();// converts List to Array

IList<string> list = strArray.ToList<string>(); // converts array into list

ToDictionary - Converts a Generic list to a generic dictionary:

Example: ToDictionary in C#:
        
IList<Student> studentList = new List<Student>() { 
                    new Student() { StudentID = 1, StudentName = "John", age = 18 } ,
                    new Student() { StudentID = 2, StudentName = "Steve",  age = 21 } ,
                    new Student() { StudentID = 3, StudentName = "Bill",  age = 18 } ,
                    new Student() { StudentID = 4, StudentName = "Ram" , age = 20 } ,
                    new Student() { StudentID = 5, StudentName = "Ron" , age = 21 } 
                };

//following converts list into dictionary where StudentId is a key
IDictionary<int, Student> studentDict = 
                                studentList.ToDictionary<Student, int>(s => s.StudentID); 

foreach(var key in studentDict.Keys)
	Console.WriteLine("Key: {0}, Value: {1}", 
                                key, (studentDict[key] as Student).StudentName);

Output:
Key: 1, Value: John 
Key: 2, Value: Steve 
Key: 3, Value: Bill 
Key: 4, Value: Ram 
Key: 5, Value: Ron

The following figure shows how studentDict in the above example contains a key-value pair, where key is a StudentID and the value is Student object.

技术分享LINQ-ToDictionary Operator

let keyword:

The ‘let‘ keyword is useful in query syntax. It projects a new range variable, allows re-use of the expression and makes the query more readable.

For example, you can compare string values and select the lowercase string value as shown below:

Example: let in LINQ query - C#
            
IList<Student> studentList = new List<Student>() { 
    new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
    new Student() { StudentID = 2, StudentName = "Steve",  Age = 21 } ,
    new Student() { StudentID = 3, StudentName = "Bill",  Age = 18 } ,
    new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
    new Student() { StudentID = 5, StudentName = "Ron" , Age = 21 } 
};

var lowercaseStudentNames = from s in studentList
                            where s.StudentName.ToLower().StartsWith("r")
                            select s.StudentName.ToLower();

As you can see, the ToLower() method is used multiple times in the above query. The following example use ‘let‘ to introduce new variable ‘lowercaseStudentName‘ that will be then used in every where. Thus, let keyword to make the query more readable.

Example: let keyword in C#
            
var lowercaseStudentNames = from s in studentList
                            let lowercaseStudentName = s.StudentName.ToLower()
                                where lowercaseStudentName.StartsWith("r")
                                select lowercaseStudentName;

foreach (var name in lowercaseStudentNames)
	Console.WriteLine(name);

Example: let keyword in VB.Net
            
Dim lowercaseStudentNames = From s In studentList
                            Let lowercaseStudentName = s.StudentName.ToLower()
                                Where lowercaseStudentName.StartsWith("r")
                                Select lowercaseStudentName;

Output:
ram 
ron

into keyword:

We have already used the ‘into‘ keyword in grouping. You can also use the ‘into‘ keyword to continue a query after a selectclause.

Example: into keyword in LINQ
            
var teenAgerStudents = from s in studentList
    where s.age > 12 && s.age < 20
    select s
        into teenStudents
        where teenStudents.StudentName.StartsWith("B")
        select teenStudents;

In the above query, the ‘into‘ keyword introduced a new range variable teenStudents, so the first range variable s goes out of scope. You can write a further query after the into keyword using a new range variable.


Select与SelectMany的区别

Select() 和 SelectMany() 的工作都是依据源值生成一个或多个结果值。

 

Select() 为每个源值生成一个结果值。因此,总体结果是一个与源集合具有相同元素数目的集合。与之相反,SelectMany() 将生成单一总体结果,其中包含来自每个源值的串联子集合。作为参数传递到 SelectMany() 的转换函数必须为每个源值返回一个可枚举值序列。然后,SelectMany() 将串联这些可枚举序列以创建一个大的序列。

 

技术分享
string[] text ={ "Albert was here", "Burke slept late", "Connor is happy" };  

var tokens = text.Select(s => s.Split(‘‘));

 foreach (string[] line in tokens)

      foreach (string token in line)        

      Console.Write("{0}.", token);


 
string[] text ={ "Albert was here", "Burke slept late", "Connor is happy" };  
var tokens = text.SelectMany(s => s.Split(‘‘));  

foreach (string token in tokens)    

  Console.Write("{0}.", token);
技术分享

 

 

下面两个插图演示了这两个方法的操作之间的概念性区别。在每种情况下,假定选择器(转换)函数从每个源值中选择一个由花卉数据组成的数组。

下图描述 Select() 如何返回一个与源集合具有相同元素数目的集合。

下图描述 SelectMany() 如何将中间数组序列串联为一个最终结果值,其中包含每个中间数组中的每个值。

 

CSDN的例子:

技术分享
class Bouquet
{
    public List<string> Flowers { get; set; }
}

static void SelectVsSelectMany()
{
    List<Bouquet> bouquets = new List<Bouquet>() {
        new Bouquet { Flowers = new List<string> { "sunflower", "daisy", "daffodil", "larkspur" }},
        new Bouquet{ Flowers = new List<string> { "tulip", "rose", "orchid" }},
        new Bouquet{ Flowers = new List<string> { "gladiolis", "lily", "snapdragon", "aster", "protea" }},
        new Bouquet{ Flowers = new List<string> { "larkspur", "lilac", "iris", "dahlia" }}
    };

    // *********** Select ***********            
    IEnumerable<List<string>> query1 = bouquets.Select(bq => bq.Flowers);

    // ********* SelectMany *********
    IEnumerable<string> query2 = bouquets.SelectMany(bq => bq.Flowers);

    Console.WriteLine("Results by using Select():");
    // Note the extra foreach loop here.
    foreach (IEnumerable<String> collection in query1)
        foreach (string item in collection)
            Console.WriteLine(item);

    Console.WriteLine("\nResults by using SelectMany():");
    foreach (string item in query2)
        Console.WriteLine(item);

    /* This code produces the following output:

       Results by using Select():
        sunflower
        daisy
        daffodil
        larkspur
        tulip
        rose
        orchid
        gladiolis
        lily
        snapdragon
        aster
        protea
        larkspur
        lilac
        iris
        dahlia

       Results by using SelectMany():
        sunflower
        daisy
        daffodil
        larkspur
        tulip
        rose
        orchid
        gladiolis
        lily
        snapdragon
        aster
        protea
        larkspur
        lilac
        iris
        dahlia
    */

}
技术分享

   Select() 和 SelectMany() 的工作都是依据源值生成一个或多个结果值。 Select() 为每个源值生成一个结果值。 因此,总体结果是一个与源集合具有相同元素数目的集合。 与之相反,SelectMany() 将生成单一总体结果,其中包含来自每个源值的串联子集合。

  SelectMany()生成的是单一的总体结果。请看SelectMany()函数的实现形式:

 

技术分享
 public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source,
Func<TSource, IEnumerable<TResult>> selector) { if (source == null) throw Error.ArgumentNull("source"); if (selector == null) throw Error.ArgumentNull("selector"); return SelectManyIterator<TSource, TResult>(source, selector); } static IEnumerable<TResult> SelectManyIterator<TSource, TResult>(IEnumerable<TSource> source,
Func<TSource, IEnumerable<TResult>> selector) { foreach (TSource element in source) { foreach (TResult subElement in selector(element)) { yield return subElement; } } }
技术分享

 

在代码中的红色部分,可以看出SelectMany()的实现过程。在第一个例子中的SelectMany()。

            string[] text ={ "Albert was here", "Burke slept late", "Connor is happy" };  
            var tokens = text.SelectMany(s => s.Split(‘‘));  

            text.SelectMany(s => s.Split(‘‘));      

可以用SelectManyIterator<TSource, TResult>(IEnumerable<TSource> source,Func<TSource, IEnumerable<TResult>> selector)替换,变成 SelectManyIterator(text,s=>s.Splt(‘ ‘));而在SelectManyIterator内部的代码相应的变为:

               foreach (string element in text) {                            text是string[]数组 

                    foreach (string subElement in s=>s.Split(‘ ‘)) {               s.Split(‘ ‘)则编程text元素生成的可枚举数组序列,IEnumerable<string>
                                yield return subElement;}}

以上转换可以看下图:

技术分享

上图中selector是Func<TSource,IEnumerable<TResult>>谓语表达式,相当于委托。示例中委托的又来克看下图。
技术分享

以上是我对Select()和SelectMany()的理解,如有错误欢迎指正:

参看CSDN的例子。网址:http://msdn.microsoft.com/zh-cn/library/bb546168.aspx#Mtps_DropDownFilterText

 

LINQ Sample

标签:set   next   object   pes   method   make   传递   format   ict   

原文地址:http://www.cnblogs.com/ioriwellings/p/7135818.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!