Как сгруппировать несколько элементов с помощью GroupBy ()? - PullRequest
6 голосов
/ 28 февраля 2010

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

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

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

  1. Можно ли улучшить дизайн?
  2. Как сгруппировать вакансии по дисциплинам и категориям работы?
  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
                             }});

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

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


Исходное решение на основе @ Obalix

Изменить 7 марта 2010 г .:

Это решение не работает - GroupBy для объекта Discipline создаст уникальную группировку для каждого объекта. Я думаю, что это связано с тем, что это ссылочный тип. Я прав? Первоначально я принял это как ответ, однако после того, как почесал голову, понял, что мои фиктивные данные сами по себе были ошибочными. Первоначальные вопросы все еще остаются без ответа.

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 ]

2 голосов
/ 28 февраля 2010

Я бы использовал синтаксис 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 
    };
2 голосов
/ 28 февраля 2010

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

Общий способ сделать это с помощью 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()
    });
0 голосов
/ 07 марта 2010

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

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

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()
              });
0 голосов
/ 01 марта 2010

Вот еще один способ, который не требует класса группировки.

ILookup<Discipline, Workcategory> result = repository
  .GetJobsWithActiveStatus()
  .Select(job => new {disc = job.disc, workCat = job.workCat})
  .Distinct()
  .ToLookup(x => x.disc, x => x.workCat);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...