代码之家  ›  专栏  ›  技术社区  ›  Ahmad

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

  •  6
  • Ahmad  · 技术社区  · 14 年前

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

    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 总是特定父母的孩子 学科 (一对多关系)。我们可以假设指定的规程和工作类别的关系始终有效。

    我面临的问题是当我试图创建一个 Grouping 基于应用于的筛选器的结果对象 Jobs . 我不确定这是否能做到,或者我所采取的方法是否正确。确切的问题本身对我来说并不清楚,但是上面定义了问题陈述。

    1. 设计可以改进吗?
    2. 如何按纪律和工作类别对工作进行分组?
    3. 我甚至需要 分组 班级?

    我已经尝试了以下操作(这是我第一次尝试使用linq),但是没有成功,因为我的理解不够完整。另一种选择是首先 学科 分组并循环通过原始分组来获取相关的 工作类别 .

    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参数导致一组项,而我正在寻找组子组结果。

    编辑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()
                  });
    
    4 回复  |  直到 14 年前
        1
  •  2
  •   AxelEckenberger    14 年前

    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);
    

    编辑: 以下是Ahmad的评论,是强类型版本:

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

    我将使用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 
        };
    
        3
  •  0
  •   Amy B    14 年前

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

    ILookup<Discipline, Workcategory> result = repository
      .GetJobsWithActiveStatus()
      .Select(job => new {disc = job.disc, workCat = job.workCat})
      .Distinct()
      .ToLookup(x => x.disc, x => x.workCat);
    
        4
  •  0
  •   Ahmad    14 年前

    这是对我有效的解决方案。

    我首先需要获取所有规程组,然后创建关联的工作类别列表 纪律性是相等的。

    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()
                  });