Paul
Paul

Reputation: 620

C# LINQ 'GroupBy' operator usage

In c#, after enumerating through a collection of 'TeamFixtureResultPage' types i am using the LINQ operator 'GroupBy' to group the items by month using the dateTime value set on the instance. As expected, when its finished processing this returns an IEnumerable<IGrouping<int, TeamFixtureResultPage>>

I would like to have the option of ordering the sorted months and the sorted team fixture result page types either ascending or descending. To achieve this at the moment i have the following code which despite producing the output i desire, it all feels a bit clunky and feels like i'm going against the DRY principles? There is probably better ways to achieve this too.

       IEnumerable<IGrouping<int, TeamFixtureResultPage>> groupedFixResList = null;

        if (teamFixResLandingPage.FixturesDisplay == "descending")
        {
            groupedFixResList = seasonLandingPage
                .Children<TeamFixtureResultPage>()
                .OrderByDescending(x => x.KickOffTime)
                .GroupBy(x => x.KickOffTime.Month)
                .OrderBy(group => group.Key)
                .Reverse();

            //example output (descending)

            //MAY
            // -Fixture 1 20/05/2020
            // -Fixture 2 15/05/2020
            // -Fixture 3 10/05/2020

            //APRIL
            // -Fixture 1 27/04/2020
            // -Fixture 2 18/04/2020
            // -Fixture 3 13/04/2020
        }
        else
        {
            groupedFixResList = seasonLandingPage
                .Children<TeamFixtureResultPage>()
                .OrderBy(x => x.KickOffTime)
                .GroupBy(x => x.KickOffTime.Month)
                .OrderBy(group => group.Key);

            //example output (ascending)

            //APRIL
            // -Fixture 3 13/04/2020
            // -Fixture 2 18/04/2020
            // -Fixture 1 27/04/2020

            //MAY
            // -Fixture 3 10/05/2020
            // -Fixture 2 15/05/2020
            // -Fixture 1 20/05/2020
        }

I have a couple of questions at this point.

Q1. Is it possible to trim this down as i'm effectively calling the following twice

groupedFixResList = seasonLandingPage
                    .Children<TeamFixtureResultPage>()

Q2. The TeamFixtureResultPage has a lot more properties than what i actually need to pass to the view so is there anyway i can create a new object all within the same LINQ statement e.g. add the following in a .Select somewhere ?

    var fixtureResult = new fixtureResult() 
    {        
       Scoreline = x.scoreline,
       FixtureDate = x.fixtureDate    
    }

I could do the following after the LINQ statements

var newGroupedFixResList = new List<FixtureResult>();

foreach (var group in groupedFixResList)
{
     foreach (var item in group)
     {
        var fixRes = new FixtureResult()
         {                 
              //map properties
         }

         newGroupedFixResList.Add(fixRes);

     }                        
 }

I have this working and may be overthinking this? Can anyone offer any advice please?

Thank you

Upvotes: 1

Views: 85

Answers (1)

Evyatar
Evyatar

Reputation: 186

you can use 1\-1 as multiplier that chooses the ordering direction, like so:

bool reverseOrder = teamFixResLandingPage.FixturesDisplay == "descending";
int orderSign = reverseOrder ? -1 : 1;
groupedFixResList = seasonLandingPage
                .Children<TeamFixtureResultPage>()
                .OrderBy(x => orderSign  * x.KickOffTime.Ticks)
                .GroupBy(x => x.KickOffTime.Month)
                .OrderBy(group => orderSign * group.Key)

I won't say it's pretty, but that's one way to do that in a single statement without code duplication.

Upvotes: 1

Related Questions