LINQ (динамический): упорядочивание внутри группы с использованием динамического linq?

#linq #linq-to-objects #dynamic-linq

#linq #linq-to-objects #динамический-linq

Вопрос:

У меня был следующий запрос с использованием обычного linq, и он отлично работал (с использованием анонимного типа),

      var result = from s in Items
            group s by s.StartTime into groupedItems
            select new {groupedItems.Key, Items= groupedItems.OrderBy(x => x.Name) };
  

Но с помощью динамического Linq я не могу упорядочить его внутри groupby.

      result = Items.GroupBy("StartTime", "it").OrderBy("Name");
  

В нем указано, что имя недоступно. Стоит отметить, что если я отключу свой порядок, все будет отлично работать, но элементы внутри каждого «ключа» не упорядочиваются.

Ответ №1:

Это хороший вопрос!

Я смоделировал вашу ситуацию, создав класс с именем Item .

 public class Item
{
    public DateTime StartTime { get; set; }
    public string Name { get; set; }
}
  

а затем создал базовый список элементов для выполнения groupby.

 List<Item> Items = new List<Item>()
{
    new Item() { StartTime = DateTime.Today, Name = "item2"},
    new Item() { StartTime = DateTime.Today, Name = "item1"},
    new Item() { StartTime = DateTime.Today.AddDays(-1), Name = "item3"},
};
  

Теперь большая разница в 2 запросах заключается в том, где выполняется order by . В первом запросе, когда вы выполняете groupedItems.OrderBy(x => x.Name) его, он выполняется для IGrouping<DateTime,Item> или для одной записи, поскольку он перебирает все группировки.

Во втором запросе порядок выполняется постфактум. Это означает, что вы выполняете упорядочивание на a IEnumerable<IGrouping<DateTime,Item>> , потому что итерации уже произошли.

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

 var expressionResult = Items.GroupBy(x => x.StartTime, 
(key, grpItems) => new { key, Items = grpItems.OrderBy(y => y.Name) });
  

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

Надеюсь, это поможет!