如何使用GroupBy()分组多个项目?

时间:2010-02-28 12:46:34

标签: 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;
   String WorkCategoryName;
}

public Class Grouping{
   Discipline parent;
   List<Workcategory> children;
}

以上模拟了Job与一个Discipline和一个WorkCategory相关联的关系。 Workcategory始终是特定父级Discipline的子级(一对多关系)。我们可以假设指定的Discipline和Workcategory的关系始终有效。

我面临的问题是,当我尝试根据应用于Grouping的过滤器创建Jobs结果对象时。我不确定如果可以做到这一点,或者我采取的方法是否正确。确切的问题本身并不清楚,但上面定义了问题陈述。

  1. 可以改进设计吗?
  2. 如何按学科和工作类别对作业进行分组?
  3. 我是否需要Grouping课程?
  4. 我尝试了以下(这是我第一次尝试使用Linq),但没有成功,因为我的理解不够完整。另一种方法是首先获取Discipline组并循环完成原始分组,然后选择相关的Workcategory

    var grouping = repository.GetJobsWithActiveStatus()
                .GroupBy(x => new {
                                      x.Discipline.DisciplineID, 
                                      x.Discipline.DisciplineName,  
                                      x.Category.WorkCategoryID, 
                                      x.Category.WorkCategoryName
                                  })
                .Select(g => new Grouping{
                                     Discipline = new Discipline{
                                                      DisciplineID = g.Key.DisciplineID, 
                                                      Name = g.Key.DisciplineName
                                                      }, 
                                     Categories = ?? // this is where I am lost
                                 }});
    

    编辑: 在发布之后,我意识到初始GroupBy参数导致一组项目,而我正在寻找Group-SubGroup结果。

    编辑2: 为了进一步澄清,我不希望关联的Jobs作为结果的一部分,而是将Discipline-Workcategory分组 - 因此Grouping类的原因


    基于@Obalix的初始解决方案

    编辑2010年3月7日:

    此解决方案不起作用 - 对象Discipline上的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()
                  });
    

4 个答案:

答案 0 :(得分:2)

Here is a description如何实现分层分组机制。

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

var list = new List<Job>();

var groupedList = list.GroupBy(x => x.disc)
    .Select(g => new {
        Key = g.Key,
        Count = g.Count(),
        WorkCategoryGroups = g.GroupBy(x => x.workCat)
    });

但是,该链接还描述了一种允许您执行以下操作的替代方法:

var groupedList = list.GroupByMany(x => x.disc, x => x.workCat);

编辑:以下艾哈迈德的评论是强类型版本:

var groupedList = list.GroupBy(x => x.disc)
    .Select(g => new Grouping {
        parent = g.Key,
        children = g.GroupBy(x => x.workCat).ToList()
    });

答案 1 :(得分:2)

我会使用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 
    };

答案 2 :(得分:0)

这是另一种不需要分组类的方法。

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

答案 3 :(得分:0)

这是适合我的解决方案。

我首先需要获得所有学科组,然后创建相关的工作类别列表 discipID相等的地方。

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()
              });
相关问题