如何使用 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)
})
我可以想出一种 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)
})