C# 如何使用GroupBy()对多个项目进行分组?

C# 如何使用GroupBy()对多个项目进行分组?,c#,linq,group-by,C#,Linq,Group By,考虑以下简化的对象和关系: public class Job{ int JobId; String name; String status; Discipline disc; WorkCategory workCat; } public class Discipline { int DisciplineId; String DisciplineName; } public class Workcategory{ int WorkCategoryId;

考虑以下简化的对象和关系:

public class Job{
  int JobId;
  String name;
  String status;
  Discipline disc;
  WorkCategory workCat;
}

public class Discipline {
  int DisciplineId;
  String DisciplineName;
}

public class Workcategory{
   int WorkCategoryId;
   String WorkCategoryName;
}

public Class Grouping{
   Discipline parent;
   List<Workcategory> children;
}
编辑: 在发布了这篇文章之后,我意识到inital GroupBy参数会产生一组item,而我正在寻找group SubGroup结果

编辑2: 为了进一步澄清,我不希望相关作业作为结果的一部分,而是希望规程工作类别分组-因此,
分组的原因是


基于@Obalix的初始解决方案

编辑2010年3月7日:

此解决方案不起作用-对象规程上的GroupBy将为每个对象生成唯一的分组。我认为这是因为它是一种引用类型。我说得对吗? 我最初接受这一点作为答案,但是在一些人意识到我的模拟数据本身是错误的之后。最初的问题仍然没有得到回答

var result = repository.GetJobsWithActiveStatus()
      .GroupBy(x => x.disc)
      .Select(g => new Grouping
              {
                  Discipline = g.Key,
                  Catergories = g.GroupBy(x=>x.workCat) // <--- The Problem is here, grouping on a reference type
                                 .Select(l=>l.Key) // needed to select the Key's only
                                 .ToList()
              });
var result=repository.getjobswitthactivestatus()
.GroupBy(x=>x.disc)
.选择(g=>新分组
{
纪律=钥匙,
Catergories=g.GroupBy(x=>x.workCat)//l.Key)//只需选择键的
托利斯先生()
});
如何实现分层分组机制

使用LINQ执行此操作的一般方法(如链接中所示)是:

编辑:在Ahmad的评论之后,这里是强类型版本:

var groupedList = list.GroupBy(x => x.disc)
    .Select(g => new Grouping {
        parent = g.Key,
        children = g.GroupBy(x => x.workCat).ToList()
    });
我会使用Linq语法:

var jobsByDiscipline = 
    from j in repository.GetJobsWithActiveStatus()
    group j by j.Discipline.DisciplineID into g
    select new { 
        DisciplineID = g.Key,
        Jobs = g.ToList() 
    };

var jobsByCategory = 
    from j in repository.GetJobsWithActiveStatus()
    group j by j.Workcategory.WorkcategoryID into g
    select new { 
        WorkcategoryID = g.Key,
        Jobs = g.ToList() 
    };
我发现这比很多带有lambda函数参数的链式方法更容易阅读

您可以通过以下方式获得分组:

var disciplineAndCategory = 
    from j in repository.GetJobsWithActiveStatus()
    group j by j.Discipline.DisciplineID into g
    let categories = 
        from j2 in g
        select j2.Workcategory.WorkcategoryID
    select new { 
        DisciplineID = g.Key,
        Jobs = categories.Distinct() // each category id once 
    };

这里有另一种不需要分组类的方法

ILookup<Discipline, Workcategory> result = repository
  .GetJobsWithActiveStatus()
  .Select(job => new {disc = job.disc, workCat = job.workCat})
  .Distinct()
  .ToLookup(x => x.disc, x => x.workCat);
ILookup结果=存储库
.getjobswitthactivestatus()
.Select(job=>new{disc=job.disc,workCat=job.workCat})
.Distinct()
.ToLookup(x=>x.disc,x=>x.workCat);

这是适合我的解决方案

我首先需要获取所有规程组,然后创建关联的工作类别列表 在这两个世界是平等的

var result = liveJobs
.GroupBy(x => new {
               x.disc.DisciplineID, 
               x.disc.DisciplineName
                  })
.Select(g => new Grouping()
              {
               parent = new Discipline(g.Key.DisciplineID,g.Key.DisciplineName),
               children = g.Where(job=>job.disc.DisciplineID == g.Key.DisciplineID) // filter the current job discipline to where the group key disciplines are equal
              .Select(j=>j.workCat)
              .ToList()
              });

+我同意,这种语法在分组时更容易阅读。@keith,谢谢你的建议,我第一次尝试使用它似乎很有效-但是没有经过测试,但是我更喜欢链式方法-我想是个人偏好:)我已经看了链接,读了评论后又看到了另一篇帖子,因此,我们将进一步了解这一点。但是,我正在寻找强类型结果(分组),然后您只需将
new{}
替换为
new StrongType{}
。使用
计数
工作类别组
的数据使用自定义成员。链接中描述的扩展方法是强类型的。仅供参考-上面答案中的帖子很棒-还有一篇关于Dynamic GroupByMany的后续帖子,如果有人感兴趣,我已经将其取消标记为答案-根据我的理解,对象上的选择和分组方式会为每个组合产生唯一的结果。即使我可以有两份工作,具有相同的学科和独特的工作理论,结果将产生两组。我认为这是因为对引用类型对象进行了比较。@Ahmad:回答你的问题时,我只能从你提供的信息中得出答案。你的解决方案与我的几乎相同——除了扩展分组——因此它会引导你找到正确的答案。拿走奖励是不好的,除非其他答案(不是你自己)从你提供的信息中提供了正确的结论。另外,每个海报都会添加一个最终帖子,并接受她/他自己的解决方案,从而拒绝奖励那些花时间引导他们找到最终解决方案的人。经过测试,结果与奥巴利克斯的答案类似。每个规程和工作类别的分组
var disciplineAndCategory = 
    from j in repository.GetJobsWithActiveStatus()
    group j by j.Discipline.DisciplineID into g
    let categories = 
        from j2 in g
        select j2.Workcategory.WorkcategoryID
    select new { 
        DisciplineID = g.Key,
        Jobs = categories.Distinct() // each category id once 
    };
ILookup<Discipline, Workcategory> result = repository
  .GetJobsWithActiveStatus()
  .Select(job => new {disc = job.disc, workCat = job.workCat})
  .Distinct()
  .ToLookup(x => x.disc, x => x.workCat);
var result = liveJobs
.GroupBy(x => new {
               x.disc.DisciplineID, 
               x.disc.DisciplineName
                  })
.Select(g => new Grouping()
              {
               parent = new Discipline(g.Key.DisciplineID,g.Key.DisciplineName),
               children = g.Where(job=>job.disc.DisciplineID == g.Key.DisciplineID) // filter the current job discipline to where the group key disciplines are equal
              .Select(j=>j.workCat)
              .ToList()
              });