Как сгруппировать несколько элементов с помощью GroupBy ()?

рассмотрим следующие упрощенные объекты и отношения:

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. The Workcategory всегда является ребенком конкретного родителя Discipline (один ко многим). Можно предположить, что связь назначенной дисциплины и рабочей категории всегда будет допустимой.

проблема я столкнулся-это когда я пытаюсь создать Grouping объект результат, основанный на фильтры, применяемые к Jobs. Я не уверен, что это можно сделать или если подход, который я принимаю, даже правильный. Сам по себе точный вопрос мне не ясен, однако вышеизложенное определяет постановку проблемы.

  1. можно улучшить?
  2. как я могу группа заданий по дисциплине и Workcategory?
  3. мне нужно Grouping класса?

я пробовал следующее (Это моя первая попытка использовать 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
                             }});

изменить: После публикации этого я понял, что параметры inital GroupBy приводят к одной группе элементов, тогда как я ищу результат Group-SubGroup.

редактирование 2: Чтобы уточнить немного дальше, я не хочу, чтобы связанные задания были частью результата, а скорее Дисциплина-группировка Workcategory-таким образом, причина Grouping класс


начальное решение на основе @Obalix

Редактировать 7-Mar-2010:

это решение не работает-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 ответов


Вот описание как можно реализовать механизм иерархической группировки.

общий способ сделать это с помощью 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);

Edit: после комментария Ахмада вот строго типизированная версия:

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

Я считаю, что легче читать, чем множество цепных методов с параметрами лямбда-функции.

Вы можете получить свои группировки из этого:

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

Это решение, которое работает для меня.

Мне нужно, чтобы получить все дисциплины группы, а затем создать связанные списки workcategory где disciplineID равны.

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