如何使用LINQ对通用列表中的值求和?

时间:2015-11-06 16:00:55

标签: 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 { get; set; }
    public Double PercentOfTotal { get; set; }
}

...我在其中存储数据。我已经有了这个通用列表来存储其中的N个:

List<ItemsForMonthYear> itemsForMonthYearList;

...然后我从该列表中读取以填充电子表格,这非常简单:

totPackagesCell.Value2 = ifmy.TotalPackages;
totPurchasesCell.Value2 = ifmy.TotalPurchases;
avgPriceCell.Value2 = ifmy.AveragePrice;

...但是所需的下一个单元格val是基于给定monthYr的所有TotalPurchases值的计算值。所以我需要计算总数的百分比&#34;所有ItemsForMonthYear&#34;记录&#34;具有相同月份的Yr值。在SQL中,我可以这样做:

SELECT SUM(TotalPurchases) FROM ItemsForMonthYear WHERE monthYr = 'Apr 14'

...然后将该结果除以每个ItemDescription的TotalPurchases值

IOW,如果该月的所有TotalPurchases的总和&#39; 4月14日&#39;是一百万美元,以及ItemDescription&#34; Cocoa Puffs&#34;的TotalPurchases。是十万美元,我可以计算出&#34; Cocoa Puffs&#34;的百分比总和。是10%。

我可以&#34;暴力强迫它&#34;并遍历整个通用列表:

Decimal allTotalPurchases;
foreach (ItemsForMonthYear ifmy in itemsForMonthYearList)
{
    if (ifmy.monthYr.Equals("Apr 14") 
    {
        allTotalPurchases = allTotalPurchases + ifmy.TotalPurchases;
    }
}

...但我认为使用LINQ可以实现更优雅/性能更友好的方式。我想这样做:

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&#34; totPurchasesForItemMonthYear &#34;将是一些价值,例如上面例子中的十万美元,以及arg&#34; totPurchasesForMonthYear &#34;将是诸如&#34; 4月14日和#34;。

之类的价值观

有没有人知道这个聪明的LINQ技巧?

5 个答案:

答案 0 :(得分:2)

您可以执行此操作来计算一个月的总购买金额:

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;

答案 1 :(得分:2)

  

所需的下一个单元格val是基于给定monthYr的所有TotalPurchases值的计算值。所以我需要计算总数的百分比&#34;所有ItemsForMonthYear&#34;记录&#34;具有相同月份的Yr值。

首先,你需要获得具有相同monthYr的那些:

var allMonthYr = itemsForMonthYearList.Where(x => x.monthYr == ifmy.monthYr);

然后它是一个简单的Sum

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];

答案 2 :(得分:2)

这是马克·布拉克特对我认为合适的解决方案的回答:

// 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];

以下是给出List<ItemsForMonthYear>的答案,并在正确填写PercentOfTotal的项目中返回List<ItemsForMonthYear>

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; }
}

输出: enter image description here

答案 3 :(得分:1)

decimal allTotalPurchases = itemsForMonthYearList.Where(s => s.monthYr.Equals("Apr 14")).Select(s => s.TotalPurchases).Sum();

答案 4 :(得分:0)

这段代码来自马克·布拉克特(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);
}

由于分组代码不能为我编译,我对上面的代码感到满意。