0

我有一个销售清单。

我还有一个十进制的财务里程碑列表,例如 100 美元、250 美元、500 美元等。

我试图找到产品达到这些里程碑的时间点。我在下面要做的是将我已经检索到的 productSales 列表放入我可以使用的结构中(实际查询执行货币转换等。我只是想让这个问题保持简单),所以对于每个里程碑,我将其转换为此 BusinessPlanningElement 列表并按 DateSold 分组。

然后我按 DateSold 排序,我的想法是检索第一个等于或大于十进制里程碑变量的元素。然后我继续获取日期,并发现 DateSold 和产品提交到系统的日期之间的差异。

foreach (decimal milestone in milestones)
{
    List<BusinessPlanningElement> MileStoneSales = (from sale in productSales
                      group sale by sale.DateSold into ds
                      select new BusinessPlanningElements
                      {
                          DateSold = ds.Key,
                          TotalSales = ds.Sum(it => it.TotalProductCut.HasValue ? it.TotalProductCut.Value : 0),
                      }).OrderBy(s => s.DateSold).ToList();


    BusinessPlanningElement bpe = MileStoneSales.Where(mss => mss.TotalSales >= milestone)
                                                .FirstOrDefault();

    if (bpe != null)
    {
        DateTime DateReached = bpe.DateSold;
        TimeSpan ts = DateReached - product.DateTimeSubmitted.Value;
        int NumberOfDays = ts.Days;

        //Output NumberOfDays
    }
    else
    {
        //Do Something Else
    }

}

如果我调试通过,我可以看到列表,并看到列表中应从此查询中检索的项目:

BusinessPlanningElement bpe = MileStoneSales.Where(mss => mss.TotalSales >= milestone)
                                            .FirstOrDefault();

然而,它似乎忽略了它,并返回一个空值给我。

有谁知道如何构造我的查询以检索列表中 TotalSales 等于或大于十进制里程碑的第一个元素?

4

2 回答 2

5

尝试使用.SkipWhile().

List<BusinessPlanningElement> MileStoneSales = (from sale in productSales
                  group sale by sale.DateSold into ds
                  select new BusinessPlanningElements
                  {
                      DateSold = ds.Key,
                      TotalSales = ds.Sum(it => it.TotalProductCut.HasValue ? it.TotalProductCut.Value : 0),
                  }).OrderBy(s => s.DateSold).ToList();

decimal accumulatedSales = 0;
BusinessPlanningElement bpe = MileStoneSales
                                .SkipWhile(mss => {
                                        accumulatedSales += mss.TotalSales;
                                        return accumulatedSales < milestone;
                                 })
                                .FirstOrDefault();
于 2012-12-06T16:09:12.617 回答
1

我冒昧地在这里重构了你的代码。如所写,您将重新计算每个里程碑的总计,但更有意义的是只计算一次运行总计,然后检查它们以找到每个里程碑。我相信这可行,但当然请测试它。

//Order the sales info by date. If it's already ordered then remove this.
productSales = productSales.OrderBy(ps => ps.DateSold).ToList();

//Compute a list of dates, with total sales up to that date
decimal runningTotal = 0m;
var salesRunningTotals = (from sale in productSales
                            select new
                            {
                                DateSold = sale.DateSold,
                                TotalSalesToDate = (runningTotal += (sale.TotalProductCut ?? 0))
                            })
                            .ToList(); 

foreach (decimal milestone in milestones)
{
    //Find the date we reached that milestone
    //If you're going to have a *lot* of dates you could remember the index of the last milestone
    //and start looking for the next one at that index
    var dateReached = (from rt in salesRunningTotals
                        where rt.TotalSalesToDate >= milestone
                        select rt.DateSold).FirstOrDefault();

    if (dateReached != null)
    {
        var bpe = productSales.Where(ps => ps.DateSold == dateReached).FirstOrDefault();

        if (bpe != null)
        {
            DateTime DateReached = bpe.DateSold;
            TimeSpan ts = DateReached - bpe.DateTimeSubmitted.Value;
            int NumberOfDays = ts.Days;

            //Output NumberOfDays
        }
        else
        {
            //Do Something Else
        }
    } 
}

另一个可能的改进——如果你还没有达到一个特定的里程碑(比如,100),那么你显然还没有达到更高的里程碑。您可以记住这一点并跳过对未来循环迭代的搜索。

于 2012-12-06T16:31:38.963 回答