Home > Net >  How to convert Row to Columns in Linq
How to convert Row to Columns in Linq

Time:12-29

I have table ReportData having below records

Agency Year Month MonthCount
One 2017 Jan 4
One 2017 Feb 6
One 2017 Nov 29
One 2017 Dec 38
One 2018 Jan 20
One 2019 Feb 18
Two 2017 Jan 24
Two 2017 Feb 66
Three 2017 Nov 9
Four 2017 Dec 8
Four 2018 Jan 22
Four 2019 Feb 48

how to convert into below table? please let me know the Linq statement. Thank you for your help in advance.

Agency Month 2017 2018 2019
One Jan 4 20 0
One Feb 6 0 18
One Nov 29 0 0
One Dec 38 0 0
Two Jan 24 0 0
Two Feb 66 0 0
Three Nov 9 0 0
Four Jan 0 22 0
Four Feb 0 0 48
Four Dec 8 0 0

source class structure

    public class ReportingData
{
    public string AgencyName { get; set; }
    public int Year { get; set; }
    public string MonthNumnber { get; set; }
    public string Month { get; set; }
    public int MonthCount { get; set; }
}

CodePudding user response:

It seems to me that per [Agency, Month] combination, you want the MonthCounts of years 2017..2019.

I wonder what you want in a few years: only the last three years? or years 2017.. 2025? But that is a later problem.

My advice would be to make Groups of ReportData with same value of [Agency, Month] combination. Use the overload of Enumerable.GroupBy that has a parameter resultSelector to precisely define the result. If your data is in a different process (usually a database), use the IQueryable version.

IEnumerable<Report> reportData = ...

// make groups with same values for [Agency, Month] combination
var result = reportData.GroupBy(report => new
{
    Agency = report.Agency,
    Month = report.Month,
},

// parameter resultSelector: for every [Agency, Month] combination,
// and all reports that have this [Agency, Month] combination,
// make one new:
(agencyMonthCombination, reports] => new
{
    Agency = agencyMonthCombination.Agency,
    Month = agencyMonthCombination.Month,

    Year2017 = reports.Where(report => report.Year == 2017)
                      .Select(report => report.MonthCount)
                      .Sum();

    Year2018 = reports.Where(report => report.Year == 2018)
                      .Select(report => report.MonthCount)
                      .Sum();

    Year2019 = reports.Where(report => report.Year == 2018)
                      .Select(report => report.MonthCount)
                      .Sum();

If you expect only one report per year, you don't have to Sum, you can just use FirstOrDefault.

You see the disadvantage of this approach of naming the years 2017..2019. Code would be much easier if you made it for all years, or the last N years:

// parameter resultSelector
(agencyMonthCombination, reports] => new
{
    Agency = agencyMonthCombination.Agency,
    Month = agencyMonthCombination.Month,

    // group the reports with this [Agency, Month] combination in years
    MonthCounts = reports.GroupBy(report => report.Year,

        (year, reportsInThisYear) => new
        {
            Year = year,
            MonthCount = reportsInThisYear.Select(report => report.MonthCount).Sum(),
        })

        // if you only want the last N: orderby descending Year and Take(N)
        .OrderByDescending(yearMonthCount => yearMonthCount.Year)
        .Take(N)

        .ToList(),
    });
  • Related