我们已经在上一节中看到了Join运算符。GroupJoin运算符执行与Join运算符相同的任务,不同之处在于GroupJoin根据指定的组键在组中返回结果。GroupJoin运算符基于键联接两个序列,并通过匹配键将结果分组,然后返回分组的结果和键的集合。
GroupJoin需要与Join相同的参数。GroupJoin具有以下两种重载方法:
GroupJoin重载方法:
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);
正如您在第一个重载中看到的,方法接受五个输入参数(除了第一个“this”参数):1)outer 2)inner 3)outerKeySelector 4)inner keyselector 5)resultSelector。请注意,resultSelector是Func委托类型,它的第二个输入参数是内部序列的IEnumerable类型。
现在,让我们使用以下Student和Standard类来了解GroupJoin,其中Student类包括与Standard类的StandardID匹配的StandardID。
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; } }
考虑下面的GroupJoin查询示例。
示例:方法语法C#中的GroupJoin
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, //内部序列 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); }
Standard 1: John, Moin, Standard 2: Bill, Ram, Standard 3:
在上面的GroupJoin查询示例中,standardList是外部序列,因为查询是从外部序列开始的。GroupJoin方法中的第一个参数是指定内部序列,在上面的示例中为studentList。该方法的第二和第三个参数GroupJoin()是指定一个字段,该字段的值应使用lambda表达式进行匹配,以便在结果中包含element。外部序列的键选择器standard => standard.StandardID指示standardList中每个元素的StandardID字段应与内部序列studentList的键匹配student => student.StandardID。如果两个键字段的值都匹配,则将该元素包括到分组集合studentsGroup中,其中键为StandardID。
Join方法中的最后一个参数是用于表达结果的表达式。在上面的示例中,结果选择器包括分组的集合studentGroup和StandardName。
下图说明了将内部序列分组到studentsGroup集合中以匹配StandardID键,并且可以使用分组的集合来表示结果。
结果集将包含具有Students和StandardFullName属性的匿名对象。学生属性将是其StandardID与Standard.StandardID匹配的Student的集合。
您可以使用“ foreach”循环访问结果。每个元素将具有StandardFullName&Students属性,其中Student将是一个集合。
foreach (var item in groupJoinResult) { Console.WriteLine(item.StandarFulldName ); foreach(var stud in item.Students) Console.WriteLine(stud.StudentName); }
以下是VB.Net中的GroupJoin示例:
示例:方法VB.Net中的GroupJoin
Dim groupJoin = standardList.GroupJoin( ' outer sequence studentList, ' inner sequence Function(s) s.StandardID, ' outerKeySelector Function(stud) stud.StandardID, ' innerKeySelector Function(s, studentGroup) New With { ' result selector .students = studentGroup, .standardName = s.StandardName }) For Each item In groupJoin Console.WriteLine(item.standardName) For Each std In item.students Console.WriteLine( std.StudentName) Next Next
Standard 1: John, Moin, Standard 2: Bill, Ram, Standard 3:
查询语法中的GroupJoin运算符与方法语法稍有不同。它需要一个外部序列,内部序列,键选择器和结果选择器。“ on”关键字用于键选择器,其中“等于”运算符的左侧是outerKeySelector,而“等于”运算符的右侧是innerKeySelector。使用into关键字创建分组的集合。
from ... in outerSequence join ... in innerSequence on outerKey equals innerKey into groupedCollection select ...
下面的示例演示了查询语法中的GroupJoin。
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); }
Dim groupJoin = From s In standardList Group Join stud In studentList On stud.StandardID Equals s.StandardID Into Group _ Select _ StudentsGroup = Group, StandardName = s.StandardName
Standard 1: John, Moin, Standard 2: Bill, Ram, Standard 3:
在VB.Net版,InTo关键字将创建一个具有相同标准的所有学生的组,并将其分配给group关键字。所以,在投影结果中使用Group。