C# LINQ-按类型分组

C# LINQ-按类型分组,c#,linq,C#,Linq,我继承了一些C代码。我不完全理解类型在LINQ上下文中是如何工作的。我有一些代码如下所示: foreach (var item in Model.Items.GroupBy(i => i.ID)) { DoStuff(item); } 我正在尝试使用更复杂的分组来更新此代码。我正在尝试按ID和DepartmentID进行分组。为了做到这一点,我有: var items = Model.Items.GroupBy(x => new { i.ID, i.DepartmentID }).

我继承了一些C代码。我不完全理解类型在LINQ上下文中是如何工作的。我有一些代码如下所示:

foreach (var item in Model.Items.GroupBy(i => i.ID))
{ DoStuff(item); }
我正在尝试使用更复杂的分组来更新此代码。我正在尝试按
ID
DepartmentID
进行分组。为了做到这一点,我有:

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>'
参数1:无法从'System.Linq.IGrouping'转换为'System.Linq.IGrouping'

从这个错误中,我可以看出,当我进行两个分组时,我基本上构建了一个新类型。但是,我不知道如何按项目的
ID
DepartmentID
对项目进行分组,然后返回一个
System.Linq.IGrouping
。我该怎么做呢?

以我的经验,匿名类型在
GroupBy
中毫无用处。我要么创建一个新类,当然不值得那么多努力,要么使用
元组

new Tuple.Create(i.ID, i.DepartmentID)
而不是您现在使用的匿名类型:

new { i.ID, i.DepartmentID })
随后链式LINQ方法中的
i
将是一个分组,而不是
对象:

.OrderBy(i => i.Name) // this will not work
在这种情况下,
i
将是一个
i分组
;也就是说,它将是一个键值对。您必须在循环通过
i分组
对象时进行排序

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);
}
var-groupings=Model.Items.GroupBy(x=>newtuple(i.ID,i.DepartmentID));
foreach(分组中的var组)
{
var groupKey=group.Key;
group=group.OrderBy(i=>i.Name),然后按降序(i=>i.OrderDate);
foreach(组中的var groupedItem)
DoStuff(groupKey,groupedItem);
}

以我的经验,匿名类型在
GroupBy
中毫无用处。我要么创建一个新类,当然不值得那么多努力,要么使用
元组

new Tuple.Create(i.ID, i.DepartmentID)
而不是您现在使用的匿名类型:

new { i.ID, i.DepartmentID })
随后链式LINQ方法中的
i
将是一个分组,而不是
对象:

.OrderBy(i => i.Name) // this will not work
在这种情况下,
i
将是一个
i分组
;也就是说,它将是一个键值对。您必须在循环通过
i分组
对象时进行排序

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);
}
var-groupings=Model.Items.GroupBy(x=>newtuple(i.ID,i.DepartmentID));
foreach(分组中的var组)
{
var groupKey=group.Key;
group=group.OrderBy(i=>i.Name),然后按降序(i=>i.OrderDate);
foreach(组中的var groupedItem)
DoStuff(groupKey,groupedItem);
}

组中的每个分组都是项目列表。您的
.OrderBy(i=>i.Name)
调用不起作用,因为您尝试排序的对象不是Model.Items对象,而是Model.Items对象和键的列表。键是使用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和by调用,以帮助显示如何使用分组键和分组中的项目。

组中的每个分组都是项目列表。您的
.OrderBy(i=>i.Name)
调用不起作用,因为您尝试排序的对象不是Model.Items对象,而是Model.Items对象和键的列表。键是使用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和by调用,以帮助显示如何使用分组键和分组中的项目。

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

执行分组后,您有许多
项目的列表
,因此,仅当您也按这些字段对项目进行分组时,按
名称
订单日期
对组进行排序才有意义:

var items = Model.Items.GroupBy(x => new {
                            i.ID, 
                            i.DepartmentID,
                            i.Name,
                            i.OrderDate })
                       .OrderBy(i => i.Name)
                       .ThenByDescending(i => i.OrderDate);
这听起来像是在改变功能,而不是你想要的。如果您希望每个分组列表按
Name
OrderDate
排序,那么您可以在分组之前对
项目进行排序,尽管我会谨慎地保留排序

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

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

执行分组后,您有许多
项目的列表
,因此,仅当您也按这些字段对项目进行分组时,按
名称
订单日期
对组进行排序才有意义:

var items = Model.Items.GroupBy(x => new {
                            i.ID, 
                            i.DepartmentID,
                            i.Name,
                            i.OrderDate })
                       .OrderBy(i => i.Name)
                       .ThenByDescending(i => i.OrderDate);
这听起来像是在改变功能,而不是你想要的。如果您希望每个分组列表按
Name
OrderDate
排序,那么您可以在分组之前对
项目进行排序,尽管我会谨慎地保留排序

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

我相信如果你想从新元组(I.ID,I.DepartmentID)到元组,你可以把它缩短。Create(I.ID,I.DepartmentID)我相信如果你想从新元组(I.ID,I.DepartmentID)到元组,你可以把它缩短。Create(I.ID,I.DepartmentID)OP希望通过
名称
订单日期
订购。OP希望通过
名称
订单日期
订购。