簡體   English   中英

如何根據月份和年份在列表中添加缺失序列?

[英]How add missing sequence in a list based on month and year?

假設我們從數據庫中獲得了這些值:

  • 月:5,總數:100,年:2019,ID:1
  • 月:7,總數:45,年:2019,ID:1
  • 月:5,總數:55,年:2019,ID:2
  • 月:9,總數:110,年:2019,ID:2

然后,我必須為第6和8個月的行生成列表中總計為0的Id:1和Id:2所缺少的行

最終結果應為:

  • 月:5,總數:100,年:2019,ID:1
  • 月:6,總數:0,年:2019,ID:1
  • 月:7,總數:45,年:2019,ID:1
  • 月:5,總數:55,年:2019,ID:2
  • 月:6,總數:0,年:2019,ID:2
  • 月:7,總數:0,年:2019,ID:2
  • 月:8,總數:0,年:2019,ID:2
  • 月:9,總數:110,年:2019,ID:2

如何使用LINQ和C#做到這一點? 如果我想到今年年底,就更難了。 g:第12個月,年份:2019年和第2個月,年份:2020年。

感謝您的任何幫助!

您想按(id和year)對記錄進行分組,並在每個組中找到邊界(第一個月和上個月)以填補空白:

    db.NAME_OF_THE_TABLE
        .ToArray() // materialize the query, since this group by is unlikely to be supported by linq2...
        .GroupBy(x => new { x.Id, x.Year }, (k, g) =>
        {
            var months = new { First = g.Min(x => x.Month), Last = g.Max(x => x.Month) };

            // left join to fill the blank between the records
            return (
                from month in Enumerable.Range(months.First, months.Last - months.First + 1)
                join row in g on month equals row.Month into match
                from x in match.DefaultIfEmpty(new TYPE_OF_RECORD { Id = k.Id, Year = k.Year, Month = month, Total = 0 })
                select x
            );
        })
        .SelectMany(g => g) // flatten the grouping

使用擴展方法來計算兩個月之間的月數:

public static class DateTimeExt {
    public static int MonthDiff(this DateTime d1, DateTime d2) => (d1.Year-d2.Year)*12+d1.Month-d2.Month;
}

您可以創建一個月份范圍,然后填寫缺少的月份。 我使用Dictionary來查找是否已經存在一個月:

var ans = db.GroupBy(r => r.ID)
            .AsEnumerable()
            .SelectMany(rg => {
                var rgd = rg.ToDictionary(r => (r.Month, r.Year));
                var First = rg.Min(r => new DateTime(r.Year, r.Month, 1));
                var Last = rg.Max(r => new DateTime(r.Year, r.Month, 1));
                return Enumerable.Range(0, Last.MonthDiff(First) + 1).Select(moffset => {
                    var wd = First.AddMonths(moffset);
                    return rgd.TryGetValue((wd.Month, wd.Year), out var r) ? r : new { ID = rg.Key, wd.Month, wd.Year, Total = 0 };
                });
            });

AsEnumerable應該將查詢信息拉到本地,以便其余的信息在LINQ to Objects中運行。

您可以生成丟失的數據並創建聯合。 例如,

var list = new []
{
    new Data{Month=5,Total=100,Year=2019,Id=1},
    new Data{Month=7,Total=100,Year=2019,Id=1},
    new Data{Month=5,Total=100,Year=2019,Id=2},
    new Data{Month=9,Total=100,Year=2019,Id=2},
    new Data{Month=2,Total=100,Year=2020,Id=2}
};

var result = list.GroupBy(x=>x.Id)
                    .Select(x=>
                    {
                        var minDate = x.ToList().Select(c=> new DateTime(c.Year,c.Month,1)).Min();
                        var maxDate = x.ToList().Select(c=> new DateTime(c.Year,c.Month,1)).Max();

                        return x.ToList().Union(Enumerable.Range(0, Int32.MaxValue)
                                         .Select(e => minDate.AddMonths(e))
                                         .TakeWhile(e => e <= maxDate)
                                         .Select(e => new Data{Month=e.Month, Total=0,Year=e.Year,Id=x.Key}))
                                         .OrderBy(v=> new DateTime(v.Year,v.Month,1))
                                         .GroupBy(c=>new {c.Month,c.Year})
                                         .Select(g=>g.First());
                    }).SelectMany(v=>v);

數據定義為

public class Data
{
    public int Month{get;set;}
    public int Year{get;set;}
    public int Total{get;set;}
    public int Id{get;set;}
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM