Linq的Group和Join操作

我断了思念

Linq的Group和Join操作

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


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

public static IEnumerable < IGrouping < TKey, TSource >> GroupBy < TSource, TKey > (
this IEnumerable < TSource > source,
Func < TSource, TKey > keySelector)


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

var result = from score in DataSource.Scores
group score by score.StudentID into scoreGroup
select scoreGroup;


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

public interface IGrouping < TKey, TElement > : IEnumerable < TElement > , IEnumerable
{
TKey Key { get ; }
}

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

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

// 输出组内成员
foreach ( var score in group )
{
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
// ...


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

var result = DataSource.Scores.GroupBy(score => score.StudentID);


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

var result = from score in DataSource.Scores
group score by score.StudentID into scoreGroup
select new { StudentID = scoreGroup.Key, Group = scoreGroup };


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

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


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


连接操作。
方法原型为:

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)


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

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

var result = from score in DataSource.Scores
join student in DataSource.Students on score.StudentID equals student.StudentID
join course in DataSource.Courses on score.CourseID equals course.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 }
// ...


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

var result =
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 });


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

var result =
from student in DataSource.Students2
join score in DataSource.Scores on student.StudentID equals score.StudentID into Scores
from score in Scores.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 }

等效的扩展方法调用实现为:
var result =
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 });


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

var result = from student in DataSource.Students
from course in DataSource.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 = }
// ...

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


连接分组。
方法原型为:

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)

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


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

var result = from item in
( from student in DataSource.Students
join score in DataSource.Scores on student.StudentID equals score.StudentID
select new { StudentName = student.Name, CourseID = score.CourseID, Value = score.Value })
group item by item.StudentName into Group
select new { StudentName = Group.Key, Group = Group };



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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值