C# 如何使用LINQ对通用列表中的值求和?
我有这门课:C# 如何使用LINQ对通用列表中的值求和?,c#,linq,generics,C#,Linq,Generics,我有这门课: public class ItemsForMonthYear { public String ItemDescription { get; set; } public String monthYr { get; set; } public int TotalPackages { get; set; } public Decimal TotalPurchases { get; set; } public Decimal AveragePrice
public class ItemsForMonthYear
{
public String ItemDescription { get; set; }
public String monthYr { get; set; }
public int TotalPackages { get; set; }
public Decimal TotalPurchases { get; set; }
public Decimal AveragePrice { get; set; }
public Double PercentOfTotal { get; set; }
}
…我在其中存储数据。我有一个通用列表,用于存储其中的N个:
List<ItemsForMonthYear> itemsForMonthYearList;
…但所需的下一个单元格val是基于给定月份的所有TotalPurchases值计算得出的。因此,我需要计算具有相同月值的所有项目的“总百分比”值。在SQL中,我可以执行以下操作:
SELECT SUM(TotalPurchases) FROM ItemsForMonthYear WHERE monthYr = 'Apr 14'
percentOfTotalCell.Value2 = GetPercentForPurchaseForMonthYearAsStr(ifmy.TotalPurchases, curMonth);
private String GetPercentForPurchaseForMonthYearAsStr(decimal totPurchasesForItemMonthYear, string totPurchasesForMonthYear)
{
percentOfTotal = // What LINQ magic goes here?
percentOfTotalStr = percentOfTotal.ToString("P", CultureInfo.InvariantCulture);
return percentOfTotalStr;
}
…然后将结果除以每个ItemDescription的TotalPurchases值
瞧,如果“4月14日”一个月的所有采购总额为100万美元,而“可可泡芙”项目的采购总额为10万美元,那么我可以计算出“可可泡芙”的总采购百分比为10%
我可以“蛮力”并循环浏览整个通用列表:
Decimal allTotalPurchases;
foreach (ItemsForMonthYear ifmy in itemsForMonthYearList)
{
if (ifmy.monthYr.Equals("Apr 14")
{
allTotalPurchases = allTotalPurchases + ifmy.TotalPurchases;
}
}
…但我认为有一种更优雅/性能更友好的方法可以使用LINQ实现这一点。我想这样做:
SELECT SUM(TotalPurchases) FROM ItemsForMonthYear WHERE monthYr = 'Apr 14'
percentOfTotalCell.Value2 = GetPercentForPurchaseForMonthYearAsStr(ifmy.TotalPurchases, curMonth);
private String GetPercentForPurchaseForMonthYearAsStr(decimal totPurchasesForItemMonthYear, string totPurchasesForMonthYear)
{
percentOfTotal = // What LINQ magic goes here?
percentOfTotalStr = percentOfTotal.ToString("P", CultureInfo.InvariantCulture);
return percentOfTotalStr;
}
…其中,arg“totPurchasesForMonthYear”将是上述示例中的十万美元,arg“totPurchasesForMonthYear”将是“Apr 14”等值
有人知道LINQ的聪明诀窍吗?你可以这样做来计算一个月的总购买量:
decimal totalPurchases = itemsForMonthYearList.Where(item => item.monthYr == "Apr 14")
.Sum(item => item.TotalPurchases);
然后,您可以通过执行以下操作来计算给定项目的百分比:
decimal percentage = (itemsForMonthYearList.Single(item => item.ItemDescription == "Cocoa Puffs")
.TotalPurchases / totalPurchases) * 100;
所需的下一个单元格值是根据给定月份的所有TotalPurchases值计算得出的。因此,我需要计算具有相同月值的所有项目的“总百分比”值
首先,您需要获得具有相同的monthYr
:
var allMonthYr = itemsForMonthYearList.Where(x => x.monthYr == ifmy.monthYr);
然后是一个简单的求和:
var totalPurchasesOfMonthYr = allMonthYr.Sum(x => x.TotalPurchases);
var percentOfTotal = ifmy.TotalPurchases / totalPurchasesOfMonthYr;
现在,这被证明是非常低效的——因为您不必要地重复了很多次这个列表。最好分组,然后求和一次:
var groupedItemsForMonthYr = itemsForMonthYearList.ToLookup(x => x.monthYr);
var totalsForMonthYr = groupedItemsForMonthYr.ToDictionary(
x => x.Key,
x => x.Sum(x => x.TotalPurchases)
);
var percentOfTotal = ifmy.TotalPurchases / totalsForMonthYr[ifmy.monthYr];
马克·布莱克特(Mark Brackett)自诩为“极为低效”的第一次拍摄的这段代码运行良好:
private String GetPercentForPurchaseForMonthYearAsStr(decimal totPurchasesForItemMonthYear, string monthToCalculate)
{
var allRecordsForMonthYr = itemsForMonthYearList.Where(x => x.monthYr == monthToCalculate);
var totalPurchasesOfMonthYr = allRecordsForMonthYr.Sum(x => x.TotalPurchases);
var percentOfTotal = totPurchasesForItemMonthYear / totalPurchasesOfMonthYr;
return percentOfTotal.ToString("P", CultureInfo.CurrentCulture);
}
由于分组代码不能为我编译,我对上面的代码很满意。这是Mark Brackett的答案,我认为是适当的修复:
// This is code that goes outside your loop
var groupedItemsForMonthYr=itemsForMonthYearList.GroupBy(x=>x.monthYr);
var totalsForMonthYr=groupedItemsForMonthYr.ToDictionary(
x => x.Key,
x => x.Sum(y => y.TotalPurchases)
);
// This is the code that goes inside your loop
var percentOfTotal = ifmy.TotalPurchases / totalsForMonthYr[ifmy.monthYr];
下面是我的答案,给出了一个列表
,并返回了一个列表
,在项目中正确填写了百分比:
var items=itemsForMonthYearList.GroupBy(x=>x.monthYr)
.Select(x=>new { total=x.Sum(y=>y.TotalPurchases), i=x })
.Select(x=>x.i.Select(y=>new ItemsForMonthYear {
ItemDescription=y.ItemDescription,
monthYr=y.monthYr,
TotalPackages=y.TotalPackages,
TotalPurchases=y.TotalPurchases,
AveragePrice=y.AveragePrice,
PercentOfTotal=(double)y.TotalPurchases/(double)x.total
}))
.SelectMany(x=>x);
以下是我的测试代码:
void Main()
{
var itemsForMonthYearList=new[]{
new ItemsForMonthYear { ItemDescription="A",monthYr="Aug 2014",TotalPackages=1,TotalPurchases=1,AveragePrice=1},
new ItemsForMonthYear { ItemDescription="A",monthYr="Sep 2014",TotalPackages=1,TotalPurchases=1,AveragePrice=1},
new ItemsForMonthYear { ItemDescription="A",monthYr="Sep 2014",TotalPackages=1,TotalPurchases=1,AveragePrice=1},
new ItemsForMonthYear { ItemDescription="A",monthYr="Oct 2014",TotalPackages=1,TotalPurchases=1,AveragePrice=1},
new ItemsForMonthYear { ItemDescription="A",monthYr="Oct 2014",TotalPackages=1,TotalPurchases=1,AveragePrice=1},
new ItemsForMonthYear { ItemDescription="A",monthYr="Oct 2014",TotalPackages=1,TotalPurchases=1,AveragePrice=1},
};
var items=itemsForMonthYearList.GroupBy(x=>x.monthYr)
.Select(x=>new { total=x.Sum(y=>y.TotalPurchases), i=x })
.Select(x=>x.i.Select(y=>new ItemsForMonthYear {
ItemDescription=y.ItemDescription,
monthYr=y.monthYr,
TotalPackages=y.TotalPackages,
TotalPurchases=y.TotalPurchases,
AveragePrice=y.AveragePrice,
PercentOfTotal=(double)y.TotalPurchases/(double)x.total
}))
.SelectMany(x=>x);
items.Dump();
}
public class ItemsForMonthYear
{
public String ItemDescription { get; set; }
public String monthYr { get; set; }
public int TotalPackages { get; set; }
public Decimal TotalPurchases { get; set; }
public Decimal AveragePrice { get; set; }
public Double PercentOfTotal { get; set; }
}
输出:
分组代码看起来很有希望,但我发现了三个错误:(1)无法将lambda表达式转换为类型“System.Collections.Generic.IEqualityComparer”,因为它不是委托类型(2)无法在此范围内声明名为“x”的局部变量,因为它将赋予“x”不同的含义,已在“父或当前”范围中用于表示其他内容(3)运算符“/”不能应用于“decimal”和“System.Linq.IGrouping”类型的操作数请参阅我的答案,了解我认为需要对上述代码进行哪些修复才能使其正确运行。