Linq: GroupBy, Sum and Count
本文关键字:and Count Sum GroupBy Linq | 更新日期: 2023-09-27 18:13:22
我有一个产品集合
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
Sampe数据:
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应该有count = 2!
我试图在一个简单的控制台应用程序中模拟这一点,但我得到了以下结果:
Product1: count 2 - Price:13 (2x6.5)
Product1: count 2 - Price:13 (2x6.5)
Product2: count 1 - Price:12 (1x12)
Product1:应该只列出一次…上面的代码可以在pastebin上找到:http://pastebin.com/cNHTBSie
我不明白第一个"样本数据的结果"是从哪里来的,但在控制台应用程序中的问题是,你正在使用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。
我还建议您应该将Quantity
和Price
属性分别更改为int
和decimal
类型-为什么要使用字符串属性用于显然不是文本的数据?
下面的查询可以工作。它使用每个组来执行选择,而不是使用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();