如何在空旷的月份获得未来12个月

Boy*_*smo 6 .net c# linq

我希望Balance从当前月份开始计算未来12个月的预测,如果该月份Balance为空,它将从最近MonthBalance值得到大于0的值.

void Main()
{
    var firstDayMonth = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
    var months = Enumerable.Range(0, 12)
                           .Select(m => new 
                            {
                                Month = firstDayMonth.AddMonths(m)
                            });

    List<SomeDate> SomeDates = new List<SomeDate>()
    {
        new SomeDate { Id = 1, Month = firstDayMonth.AddMonths(0), Balance = 1m },
        new SomeDate { Id = 2, Month = firstDayMonth.AddMonths(2), Balance = 1m },
        new SomeDate { Id = 3, Month = firstDayMonth.AddMonths(1), Balance = 6m },
        new SomeDate { Id = 4, Month = firstDayMonth.AddMonths(2), Balance = 5m },
        new SomeDate { Id = 5, Month = firstDayMonth.AddMonths(3), Balance = 3m },
        new SomeDate { Id = 6, Month = firstDayMonth.AddMonths(2), Balance = 2m },
        new SomeDate { Id = 7, Month = firstDayMonth.AddMonths(3), Balance = 4m },
        new SomeDate { Id = 8, Month = firstDayMonth.AddMonths(1), Balance = 2m },
        new SomeDate { Id = 9, Month = firstDayMonth.AddMonths(3), Balance = 3m },
    };

    var groupedMonths = SomeDates
                        .GroupBy(c => c.Month)
                        .Select(g => new 
                        {
                            Month = g.Key,
                            SumBalance = g.Sum(s => s.Balance)
                        });

    var Projected12MonthsBalance = from m in months
                                   join gm in groupedMonths on m.Month equals gm.Month into mm
                                   from gm in mm.DefaultIfEmpty()
                                   select new 
                                    {
                                        Month = m.Month, 
                                        Balance = gm == null ? 0m : gm.SumBalance
                                    };

    Console.WriteLine(Projected12MonthsBalance);
}

// Define other methods and classes here
public class SomeDate 
{
    public int Id { get; set; }
    public DateTime Month { get; set; }
    public decimal Balance { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这是我到目前为止所尝试的.这将导致:

Month     | Balance
7/1/2015  | 1
8/1/2015  | 8
9/1/2015  | 8
10/1/2015 | 10
11/1/2015 | 0
...
6/1/2016  | 0
Run Code Online (Sandbox Code Playgroud)

有可能得到一个像这样的结果:

Month     | Balance
7/1/2015  | 1
8/1/2015  | 8
9/1/2015  | 8
10/1/2015 | 10
11/1/2015 | 10 <-- gets the value from the nearest month with Balance greater than 0
...
6/1/2016  | 10 <-- gets the value from the nearest month with Balance greater than 0
Run Code Online (Sandbox Code Playgroud)

我似乎无法完成查询所以我现在设置了零.任何帮助将非常感激.谢谢!

Eni*_*ity 5

对于LINQ,恕我直言,这似乎相当容易.

首先,我修改了months以避免使用匿名类型(因为它没有必要).

var months =
    Enumerable
        .Range(0, 12)
        .Select(m => firstDayMonth.AddMonths(m));
Run Code Online (Sandbox Code Playgroud)

然后我按月创建了余额数据的查找:

var lookup =
    SomeDates
        .ToLookup(x => x.Month, x => x.Balance);
Run Code Online (Sandbox Code Playgroud)

查找更好的是分组或字典,您可以询问查找的值,其中密钥不存在并返回空列表.它减少了在检索值之前检查密钥是否存在的需要.

我将用于.Aggregate(...)构建最终列表,因此我需要accumulator为聚合函数创建初始化:

var accumulator =
    months
        .Take(1)
        .Select(m => new { Month = m, Balance = lookup[m].Sum() })
        .ToList();
Run Code Online (Sandbox Code Playgroud)

这只是计算第一个月余额并将其添加到列表中的结果.这是一个匿名类型的列表.

现在最后的查询非常简单:

var Projected12MonthsBalance =
    months
        .Skip(1)
        .Aggregate(
            accumulator,
            (a, m) =>
            {
                var b = lookup[m].Sum();
                b = b == 0 ? a.Last().Balance : b;
                a.Add(new { Month = m, Balance = b });
                return a;
            });
Run Code Online (Sandbox Code Playgroud)

此查询会跳过第一个月,因为我们已将其添加到累加器中.lamdba函数现在只计算每个月的余额,如果它为零,则取代前一个月的余额.

这是我得到的结果:

结果