如何使用 LINQ 按一个字段分组,在该分组内排序,然后对该组合的值求和?

How to use LINQ to group by one field, sort within that grouping, and sum values for that combination?

我可以想出一种 Rube Goldberg 式的方法来做到这一点,但我认为使用 LINQ 可以更优雅、更简洁地完成它:

使用此 class 的通用实例列表:

public class PlatypusData
{
    public String MemberName { get; set; }
    public String CompanyName { get; set; }
    public String ReasonDescription { get; set; }
    public String TransactionType { get; set; }
    public int QtyOrdered { get; set; }
    public int QtyShipped { get; set; }
}

我想将其压缩为前四个 class 成员(MemberName、CompanyName、ReasonDescription、TransactionType)的唯一值的行或记录。

例如,使用这样定义的通用列表:

List<PlatypusData> _platypusDataList = new List<PlatypusData>();

...此通用列表的内容可能是以下数据:

MemberName = "Ollie of Burkina Faso"
CompanyName = "Riley's Rugbeaters"
ReasonDescription = "Credit - Failed to deliver item (for credit adjustments only)"
TransactionType = "CREDIT ITEM"
QtyOrdered = 1
QtyShipped = 1

MemberName = "Oscar of Redlands"
CompanyName = "Herrera's Empty Frames"
ReasonDescription = [blank]
TransactionType = "REGULAR ITEM - ON SPEC"
QtyOrdered = 7
QtyShipped = 6

MemberName = "Ollie of Burkina Faso"
CompanyName = "Gatherer Mechanics"
ReasonDescription = "Credit - Product Quality (for credit adjutments only)"
TransactionType = "CREDIT ITEM"
QtyOrdered = 3
QtyShipped = 3

MemberName = "Ollie of Burkina Faso"
CompanyName = "Riley's Rugbeaters"
ReasonDescription = [blank]
TransactionType = "REGULAR ITEM - ON SPEC"
QtyOrdered = 42
QtyShipped = 42

MemberName = "Oscar of Redlands"
CompanyName = "Fidelity Fire"
ReasonDescription = "Credit - Failed to deliver item (for credit adjustments only)"
TransactionType = "REGULAR ITEM - ON SPEC"
QtyOrdered = 5
QtyShipped = 4

MemberName = "Oscar of Redlands"
CompanyName = "Herrera's Empty Frames"
ReasonDescription = [blank]
TransactionType = "REGULAR ITEM - ON SPEC"
QtyOrdered = 7
QtyShipped = 7

MemberName = "Ollie of Burkina Faso"
CompanyName = "Gatherer Mechanics"
ReasonDescription = [blank]
TransactionType = "REGULAR ITEM - ON SPEC"
QtyOrdered = 11
QtyShipped = 10

MemberName = "Oscar of Redlands"
CompanyName = "Fidelity Fire"
ReasonDescription = [blank]
TransactionType = "REGULAR ITEM - ON SPEC"
QtyOrdered = 6
QtyShipped = 7

MemberName = "Oscar of Redlands"
CompanyName = "Fidelity Fire"
ReasonDescription = [blank]
TransactionType = "REGULAR ITEM - ON SPEC"
QtyOrdered = 8
QtyShipped = 8

MemberName = "Ollie of Burkina Faso"
CompanyName = "Gatherer Mechanics"
ReasonDescription = [blank]
TransactionType = "REGULAR ITEM - ON SPEC"
QtyOrdered = 12
QtyShipped = 12

...对于 MemberName+CompanyName+ReasonDescription+TransactionType 的每个唯一组合,我想从中将它压缩到一行,组合行的 QtyOrdered 和 QtyShipped 是这些值的总和,数据从按 MemberName、CompanyName、ReasonDescription 排序的 LINQ 操作返回,例如:

MemberName = "Ollie of Burkina Faso"
CompanyName = "Gatherer Mechanics"
ReasonDescription = [blank]
TransactionType = "REGULAR ITEM - ON SPEC"
QtyOrdered = 23
QtyShipped = 22

MemberName = "Ollie of Burkina Faso"
CompanyName = "Gatherer Mechanics"
ReasonDescription = "Credit - Product Quality (for credit adjutments only)"
TransactionType = "CREDIT ITEM"
QtyOrdered = 3
QtyShipped = 3

MemberName = "Ollie of Burkina Faso"
CompanyName = "Riley's Rugbeaters"
ReasonDescription = [blank]
TransactionType = "REGULAR ITEM - ON SPEC"
QtyOrdered = 42
QtyShipped = 42

MemberName = "Ollie of Burkina Faso"
CompanyName = "Riley's Rugbeaters"
ReasonDescription = "Credit - Failed to deliver item (for credit adjustments only)"
TransactionType = "CREDIT ITEM"
QtyOrdered = 1
QtyShipped = 1


MemberName = "Oscar of Redlands"
CompanyName = "Fidelity Fire"
ReasonDescription = [blank]
TransactionType = "REGULAR ITEM - ON SPEC"
QtyOrdered = 14
QtyShipped = 15

MemberName = "Oscar of Redlands"
CompanyName = "Fidelity Fire"
ReasonDescription = "Credit - Failed to deliver item (for credit adjustments only)"
TransactionType = "REGULAR ITEM - ON SPEC"
QtyOrdered = 5
QtyShipped = 4

MemberName = "Oscar of Redlands"
CompanyName = "Herrera's Empty Frames"
ReasonDescription = [blank]
TransactionType = "REGULAR ITEM - ON SPEC"
QtyOrdered = 14
QtyShipped = 13

我认为需要 GroupBy、OrderBy 和 Sum 的某种组合,但不知道如何去做(以 LINQ/non-Goldbergesque 方式)。

I reckon some combination of GroupBy, OrderBy, and Sum is needed

你是对的。这应该是你需要的:

var result = _platypusDataList
    .GroupBy(i => new { i.MemberName, i.CompanyName, i.ReasonDescription, i.TransactionType })
    .Select(g => new
        {
            g.Key.MemberName,
            g.Key.CompanyName,
            g.Key.ReasonDescription,
            g.Key.TransactionType,
            QtyOrdered = g.Sum(i => i.QtyOrdered),
            QtyShipped = g.Sum(i => i.QtyShipped)
        })
    .OrderBy(i => i.MemberName)
    .ThenBy(i => i.CompanyName)
    .ThenBy(i => i.ReasonDescription)
    .ToList();

上面的代码returns一个匿名类型的列表。如果你想要一个List<PlatypusData>,你需要修改Select

.Select(g => new PlatypusData
    {
        MemberName = g.Key.MemberName,
        CompanyName = g.Key.CompanyName,
        ReasonDescription = g.Key.ReasonDescription,
        TransactionType = g.Key.TransactionType,
        QtyOrdered = g.Sum(i => i.QtyOrdered),
        QtyShipped = g.Sum(i => i.QtyShipped)
    })