LINQ - GroupBy Type

本文关键字:Type GroupBy LINQ | 更新日期: 2023-09-27 18:17:48

我继承了一些c#代码。我不完全理解类型在LINQ上下文中是如何工作的。我有一些像这样的代码:

foreach (var item in Model.Items.GroupBy(i => i.ID))
{ DoStuff(item); }

我正在尝试用更复杂的分组更新此代码。我试着用IDDepartmentID来分组。为了做到这一点,我有:

var items = Model.Items.GroupBy(x => new { i.ID, i.DepartmentID }).OrderBy(i => i.Name).ThenByDescending(i => i.OrderDate);
foreach (var item in items) 
{ DoStuff(item); }

当我编译我的代码,我得到一个编译时错误说:

Argument 1: cannot convert from 'System.Linq.IGrouping<<anonymous type:string ID, int DepartmentID>, MyProject.Item>' to 'System.Linq.IGrouping<MyProject.Item>'

从这个错误中,我可以看出,当我进行两个分组时,我基本上构建了一个新类型。然而,我不知道如何通过它们的IDDepartmentID来分组我的项目,然后只返回System.Linq.IGrouping<MyProject.Item>。我怎么做呢?

LINQ - GroupBy Type

您的分组是正确的,但是您的排序导致了问题。

在你完成分组之后,你有很多Item的列表,所以按NameOrderDate排序的组只有在你按这些字段分组的时候才有意义:

var items = Model.Items.GroupBy(x => new {
                            i.ID, 
                            i.DepartmentID,
                            i.Name,
                            i.OrderDate })
                       .OrderBy(i => i.Name)
                       .ThenByDescending(i => i.OrderDate);

这听起来像是在改变功能,而不是你想要的。如果您希望每个分组列表按NameOrderDate排序,那么您可以在分组之前对Item s进行排序,尽管我会谨慎地保留顺序

var itemGroups = Model.Items.OrderBy(i => i.Name)
                       .ThenByDescending(i => i.OrderDate)
                       .GroupBy(x => new {
                            i.ID, 
                            i.DepartmentID,
                            i.Name,
                            i.OrderDate });

或者,最好是在读取时对每个列表进行排序。

foreach(var itemGroup in itemGroups)
{
    var orderedgroup = itemGroup.OrderBy(i => i.Name)
                                .ThenByDescending(i => i.OrderDate)
}

根据我的经验,匿名类型对GroupBy没有任何帮助。我会创建一个新的类,如果它不值得那么多的努力,使用Tuple:

new Tuple.Create(i.ID, i.DepartmentID)

这不是你现在使用的匿名类型:

new { i.ID, i.DepartmentID })

那么i在随后的链式LINQ方法中将是一个分组,而不是Items对象:

.OrderBy(i => i.Name) // this will not work

本例中的i将是IGrouping<Tuple<int, int>, Model.Items>;也就是说,它将是一个键值对。您必须在循环遍历IGrouping对象时进行排序。

var groupings = Model.Items.GroupBy(x => new Tuple<int, int>(i.ID, i.DepartmentID));
foreach (var group in groupings)
{
    var groupKey = group.Key;
    group = group.OrderBy(i => i.Name).ThenByDescending(i => i.OrderDate);
    foreach (var groupedItem in group)
        DoStuff(groupKey, groupedItem);
}

组中的每个分组都是一个项目列表。您的.OrderBy(i => i.Name)调用不起作用,因为您试图订购的对象不是Model。对象,而是Model的列表。item对象与键。键是使用ID和DepartmentID属性创建的匿名对象。

对于分组,通常会有两个嵌套循环,而不仅仅是一个。外部循环遍历每个分组。内部循环遍历分组中的每个项。你可以这样做:

foreach(var grouping in Model.Items
    .GroupBy(x => new { i.ID, i.DepartmentID })
    .OrderBy(b => b.Key.DepartmentID)
    .ThenBy(t => t.Key.ID))
{
    Console.WriteLine("{0}, {1}", grouping.Key.DepartmentID, grouping.Key.ID);
    foreach(var item in grouping.OrderBy(n => n.Name).ThenByDescending(i => i.OrderDate))
    {
        Console.WriteLine("'t{0}", item.Name)
    }
}

我添加了OrderBy和ThenBy调用,以帮助展示如何处理分组键和分组中的项。