2010-08-08 2 views
4

Я использую GroupBy для создания иерархического набора групп для использования в нескольких дочерних сетках.GroupBy с несколькими группами в качестве иерархии

Предположим, у меня есть запрос с 6 столбцами, a, b, c, d, e, f.

Теперь мне нужно сгруппировать по a, затем по b, затем c. и вернуть всю строку в группе c.

var q = rows.GroupBy(x => x.a) 

Хорошо, это хорошо. Это дает мне мою группу. Затем мы будем группировать их по а и b.

var q1 = q.Select(g =>new { 
    Key = g.Key, 
    SubGroup = g.GroupBy(x => x.b) 
} 

Хорошо, это также хорошо работает. Я получаю свою группу с подгруппами b.

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

var q2 = q1.Select(g1 => new { 
    Key = g1.Key, 
    SubGroup = g1.GroupBy(x => x.c) 
} 

Это не скомпилировано. Сообщает, что Group1 не существует на g1.

var q2 = q.Select(g1 => new { 
    Key = g1.Key, 
    SubGroup = g1.GroupBy(x => x.c) 
} 

Это не дает мне подгруппу b, только a и c.

Любая идея о том, что я делаю неправильно здесь?

EDIT:

Этот также не работает, говоря, что нет определения для g1.Key

var q2 = q.Select(g => new { 
    Key = g.Key, 
    SubGroup = g.Select(g1 => new { 
      Key = g1.Key 
      SubGroup = g1.GroupBy(a => a.c) 
     }) 

У меня есть такое плохое понимание о том, что это делает внутренне.

+0

г просто список ваших сущностей и вы говорите g.select, который дает вам объект, но у него нет ключа –

+0

Да, я получаю это. Я просто не соединяю точки и выясняю, что это за решение. –

ответ

5

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

Но если вы хотите использовать GroupBy и IGroupings, чтобы управлять им, вы работаете с ним с неправильного конца. Сначала вы хотите начать с самого глубокого уровня и работать.

var groups = rows 
    .GroupBy(x => new { x.A, x.B, x.C, x.D, x.E, x.F }) 
    .GroupBy(x => new { x.Key.A, x.Key.B, x.Key.C, x.Key.D, x.Key.E }) 
    .GroupBy(x => new { x.Key.A, x.Key.B, x.Key.C, x.Key.D, }) 
    .GroupBy(x => new { x.Key.A, x.Key.B, x.Key.C }) 
    .GroupBy(x => new { x.Key.A, x.Key.B }) 
    .GroupBy(x => x.Key.A); 

groups.First().Key;    // will be an A value 
groups.First().First().First(); // will be an A, B, C group 
+0

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

+0

Да, похоже, что несколько полей необходимы, чтобы заставить нижние группы работать. Ты да, человек! Если вы не женщина, и в этом случае вы да женщина! –

+0

В качестве бонуса, если я конвертирую свой запрос Linq-to-Sql в список до выполнения группировки, то он значительно быстрее, потому что он делает это в памяти, а не с несколькими запросами на сервере sql. Добавляет небольшую нагрузку на веб-сервер, но я думаю, что это чистая победа. –

2

GroupBy фактически поддерживает предоставление списка элементов для группировки. Каждая группа будет содержать те же первые 3 элемента (A, B & C). Вы можете получить ключ с помощью метода .Key и поиграть с разными строками с помощью foreach. См Пример:

var groups = Elements.GroupBy(x => new {x.A, x.B, x.C}); 
    foreach (var group in groups) 
    { 
     Trace.WriteLine(group.Key + ": " + group.Count()); 
     foreach (var row in group) 
     { 
      Trace.WriteLine(row.D); 
     } 
    } 

Edit: Ааа, хорошо - то, что вам нужно, это то:

var groups = Elements 
     .GroupBy(a => new {a.A}) 
     .Select(g1 => new { 
      A = g1.Key, 
      Groups = g1 
      .GroupBy(b=> new {b.B}) 
      .Select(g2 => new { 
       B = g2.Key, 
       Groups = g2 
       .GroupBy(c => new {c.C}) 
       .Select(g3 => new { 
        C = g3.Key, 
        Rows = g3 
       }) 
      }) 
     }); 

    foreach (var groupA in groups) 
    { 
     Trace.WriteLine(groupA.A); 
     foreach (var groupB in groupA.Groups) 
     { 
      Trace.WriteLine("\t" + groupB.B); 
      foreach (var groupC in groupB.Groups) 
      { 
       Trace.WriteLine("\t\t" + groupC.C); 
       foreach (var row in groupC.Rows) 
       { 
        Trace.WriteLine("Row: " + row.ToString()); 
       } 
      } 
     } 
    } 
+0

Нет, это создает одну группу с a, b и c. Не коллекции каждого. –

+0

ОК - я изменил его, чтобы вложить группы для вас - лучше, чем другой ответ, поскольку вам не нужно делать все чрезмерное вложение/несколько полей и т. Д. –

+0

Да, это было на самом деле вроде того, где я пытался изначально , и теперь я вижу, что я сделал не так. Тем не менее, ответ mquander действительно больше того, что я * имел в виду, а не того, что я делал. Причина в том, что все функции в hiearchy - это IGroupings, а не сочетание групп и IOrderedQueryables, что и делает ваше решение. Но я буду +1 тебе –

Смежные вопросы