Linq: GroupBy,Sum and Count

我有一系列的产品

public class Product {


public Product() { }


public string ProductCode {get; set;}
public decimal Price {get; set; }
public string Name {get; set;}
}

现在我想根据产品代码对集合进行分组,并返回一个对象,其中包含名称、每个代码的数字或产品以及每个产品的总价格。

public class ResultLine{


public ResultLine() { }


public string ProductName {get; set;}
public string Price {get; set; }
public string Quantity {get; set;}
}

因此,我使用 GroupBy 按 ProductCode 进行分组,然后计算总和,并计算每个产品代码的记录数。

以下是我目前掌握的情况:

List<Product> Lines = LoadProducts();
List<ResultLine> result = Lines
.GroupBy(l => l.ProductCode)
.SelectMany(cl => cl.Select(
csLine => new ResultLine
{
ProductName =csLine.Name,
Quantity = cl.Count().ToString(),
Price = cl.Sum(c => c.Price).ToString(),
})).ToList<ResultLine>();

由于某些原因,总和被正确地执行,但计数总是1。

样本数据:

List<CartLine> Lines = new List<CartLine>();
Lines.Add(new CartLine() { ProductCode = "p1", Price = 6.5M, Name = "Product1" });
Lines.Add(new CartLine() { ProductCode = "p1", Price = 6.5M, Name = "Product1" });
Lines.Add(new CartLine() { ProductCode = "p2", Price = 12M, Name = "Product2" });

样本数据的结果:

Product1: count 1   - Price:13 (2x6.5)
Product2: count 1   - Price:12 (1x12)

产品1应该有计数 = 2!

我试图用一个简单的控制台应用模拟这个过程,但是我得到了以下结果:

Product1: count 2   - Price:13 (2x6.5)
Product1: count 2   - Price:13 (2x6.5)
Product2: count 1   - Price:12 (1x12)

产品1: 应该只列出一次..。 上述代码可以在 pastebin 上找到: < a href = “ http://pastebin.com/cnHTBsie”> http://pastebin.com/cnhtbsie

382056 次浏览

我不明白第一个“带有样本数据的结果”是从哪里来的,但是控制台应用程序中的问题是您正在使用 SelectMany查看 每组的每个项目

我觉得你只是想:

List<ResultLine> result = Lines
.GroupBy(l => l.ProductCode)
.Select(cl => new ResultLine
{
ProductName = cl.First().Name,
Quantity = cl.Count().ToString(),
Price = cl.Sum(c => c.Price).ToString(),
}).ToList();

这里使用 First()获取产品名称的前提是,具有相同产品代码的每个产品都具有相同的产品名称。正如注释中提到的,您可以按产品名称和产品代码进行分组,如果对于任何给定的代码,名称总是相同,那么结果将是相同的,但显然在 EF 中会生成更好的 SQL。

我还建议您将 QuantityPrice属性分别更改为 intdecimal类型-为什么对明显不是文本的数据使用字符串属性?

下面的查询可以工作。它使用每个组代替 SelectMany进行选择。SelectMany处理每个集合中的每个元素。例如,在查询中有两个集合的结果。SelectMany获取所有结果,总共3个,而不是每个集合。下面的代码处理 select 部分中的每个 IGrouping,以使聚合操作正常工作。

var results = from line in Lines
group line by line.ProductCode into g
select new ResultLine {
ProductName = g.First().Name,
Price = g.Sum(pc => pc.Price).ToString(),
Quantity = g.Count().ToString(),
};

有时你需要通过 FirstOrDefault()或者 singleOrDefault()选择一些字段,你可以使用下面的查询:

List<ResultLine> result = Lines
.GroupBy(l => l.ProductCode)
.Select(cl => new Models.ResultLine
{
ProductName = cl.select(x=>x.Name).FirstOrDefault(),
Quantity = cl.Count().ToString(),
Price = cl.Sum(c => c.Price).ToString(),
}).ToList();