Linq的Group和Join操作

我断了思念

Linq的Group和Join操作

本篇介绍Linq的Group和Join操作。


Group是进行分组操作,同SQL中的Group By类似。
原型如下:

publicstaticIEnumerable<IGrouping<TKey, TSource>>GroupBy<TSource, TKey>(
thisIEnumerable<TSource>source,
Func
<TSource, TKey>keySelector)


它有几个重载,返回类型有两种:IEnumerable<IGrouping<TKey, TSource>> 和 IEnumerable<TResult>。
返回类型为:IEnumerable<IGrouping<TKey, TSource>>
示例:
返回按学号分组学生的成绩

varresult =fromscore inDataSource.Scores
groupscore byscore.StudentID intoscoreGroup
select scoreGroup;


scoreGroup为IGrouping<TKey, TSource>类型,返回结果为IEnumerable<IGrouping<TKey, TSource>>,既集合的集合,因此输出时需用双重循环。
IGrouping<TKey, TElement>接口定义为:

publicinterfaceIGrouping<TKey, TElement>: IEnumerable<TElement>, IEnumerable
{
TKey Key {
get; }
}

其中Key为分组依据的字段。

foreach(vargroupinresult)
{
//输出分组依据的字段
Console.WriteLine("/nStudent ID:"+group.Key);

//输出组内成员
foreach(varscore ingroup)
{
Console.WriteLine(score);
}
}

//result:
//Student ID:1
//Student ID:1,Course ID:1,Score:78
//Student ID:1,Course ID:2,Score:60
//...

//Student ID:2
//Student ID:2,Course ID:1,Score:59
//...


等效的扩展方法调用实现为:

varresult =DataSource.Scores.GroupBy(score =>score.StudentID);


返回类型为:IEnumerable<TResult>
对分组结果进行一些包装,如包装为匿名类型。
返回按学号分组学生的成绩

varresult =fromscore inDataSource.Scores
groupscore byscore.StudentID intoscoreGroup
select
new{ StudentID =scoreGroup.Key, Group =scoreGroup };


匿名类型中Group为IGrouping<TKey, TSource>类型。
等效的扩展方法调用实现为:

varresult =DataSource.Scores.GroupBy(score =>score.StudentID,
(key,
group) =>new{ StudentID =key, Group =group});


其他一些重载使用方法类似。


连接操作。
方法原型为:

publicstaticIEnumerable<TResult>Join<TOuter, TInner, TKey, TResult>(
thisIEnumerable<TOuter>outer,
IEnumerable
<TInner>inner,
Func
<TOuter, TKey>outerKeySelector,
Func
<TInner, TKey>innerKeySelector,
Func
<TOuter, TInner, TResult>resultSelector)


从Join方法原型可以看出其使用方法。

内连接
选择左右两侧集合都含有相对应的元素。
示例:
查询学生的姓名、学科、成绩。

varresult =fromscore inDataSource.Scores
joinstudent inDataSource.Students onscore.StudentID equalsstudent.StudentID
joincourse inDataSource.Courses onscore.CourseID equalscourse.CourseID
select
new{ StudentName =student.Name, CourseName =course.CourseName, ScoreValue =score.Value };
//result
//{ StudentName = Andy, CourseName = C Language, ScoreValue = 78 }
//{ StudentName = Andy, CourseName = Biophysics, ScoreValue = 60 }
//...
//{ StudentName = Bill, CourseName = C Language, ScoreValue = 59 }
//{ StudentName = Cindy, CourseName = Biophysics, ScoreValue = 60 }
//...


等效的扩展方法调用实现为:

varresult =
DataSource.Scores.Join(
DataSource.Students,
score
=>score.StudentID,
student
=>student.StudentID,
(score, student)
=>new{ StudentName =student.StudentID, ScoreValue =score.Value, CourseID =score.CourseID })
.Join(DataSource.Courses,
scostu
=>scostu.CourseID,
course
=>course.CourseID,
(scostu, course)
=>new{ StudentName =scostu.StudentName, CourseName =course.CourseName, ScoreValue =scostu.ScoreValue });


左外连接
当右侧的连接的右侧没有左侧对应的元素时,内连接会忽略左侧元素。要想保留左侧元素,可以使用做外连接。右侧被置为默认值,如:引用类型被置为空。
示例:

varresult =
fromstudent inDataSource.Students2
joinscore inDataSource.Scores onstudent.StudentID equalsscore.StudentID intoScores
fromscore inScores.DefaultIfEmpty()
select
new{ student =student, score =score ==default(Score) ?0: score.Value };
//result:
//{ student = Student ID:5,Student Name:Erik, score = 78 }
//{ student = Student ID:6,Student Name:Frank, score = 0 }

等效的扩展方法调用实现为:
varresult =
DataSource.Students2.GroupJoin(
DataSource.Scores,
student
=>student.StudentID,
score
=>score.StudentID,
(student, Scores)
=>new{ student =student, Scores =Scores })
.SelectMany(
group=>group.Scores.DefaultIfEmpty(),
(
group, score) =>new{ student =group.student, score =(score ==null) ?0.0: score.Value });


笛卡尔积
集合中的元素交错连接。
示例:统计学生课程成绩时的模板。

varresult =fromstudent inDataSource.Students
fromcourse inDataSource.Courses
select
new{ StudentName =student.Name, CourseName =course.CourseName, ScoreValue =(double?)null};
//result:
//{ StudentName = Andy, CourseName = C Language, ScoreValue = }
//{ StudentName = Andy, CourseName = Biophysics, ScoreValue = }
//...
//{ StudentName = Bill, CourseName = C Language, ScoreValue = }
//...
//{ StudentName = Cindy, CourseName = Fundamentals of Compiling, ScoreValue = }
//...

等效的扩展方法调用实现为:
varresult =DataSource.Students.SelectMany(
student
=>DataSource.Courses
.Select(
course
=>
new{ StudentName =student.Name, CourseName =course.CourseName, ScoreValue =(double?)null}));


连接分组。
方法原型为:

publicstaticIEnumerable<TResult>GroupJoin<TOuter, TInner, TKey, TResult>(
thisIEnumerable<TOuter>outer,
IEnumerable
<TInner>inner,
Func
<TOuter, TKey>outerKeySelector,
Func
<TInner, TKey>innerKeySelector,
Func
<TOuter, IEnumerable<TInner>, TResult>resultSelector)

//result:
//Andy
//1----78
//2----60
//...
//Bill
//1----59
//...
//Cindy
//2----60
//...


相当于组合了Group操作和Join操作。等效的操作如下:

varresult =fromitem in
(
fromstudent inDataSource.Students
joinscore inDataSource.Scores onstudent.StudentID equalsscore.StudentID
select
new{ StudentName =student.Name, CourseID =score.CourseID, Value =score.Value })
groupitem byitem.StudentName intoGroup
select
new{ StudentName =Group.Key, Group =Group };



到现在,Linq与SQL语言等价的操作基本介绍完,组合这些操作能实现复杂的查询。

展开阅读全文

没有更多推荐了,返回首页