Lambda Groupby by year and month

Asked

Viewed 1,625 times

11

I have a list of events, and I’d like to group them by year and month, for example

[Year 2017]
Month January
{ Event 1, Event 2, Event 2 }

Month February
{ Event 3 }

[Year 2018]
Month January
{ Event 4, Event 5 }

I’m using Lambda in C#, I have something like this already:

var groupLista = listaDeEventos.GroupBy(x => new {x.Data.Year, x.Data.Month})....

2 answers

13


Basically, there are two ways to do this.

The complicated way, where it is necessary to make one grouping per year and another month, being this second within the first (Okay, it’s not that complicated).

And also the easy way, which would be to group directly per month and per year together, ie to concatenate month of year in a way that they are unique keys to the grouping.

If it is necessary to maintain a hierarchy (event -> month -> year), use the complicated form. Otherwise, I see no reason not to use the simplest form.

The code at the end of the post has an example of each of the two ways.

It is also possible to make a "double" grouping, the way you showed in the question, just to illustrate, would be this way:

var grupo= listaEventos.GroupBy(x => new { x.Data.Year, x.Data.Month }) 
                       .Select(g => new { Key = g.Key, Itens = g.ToList() });

foreach(var i in grupo1)
{
    WriteLine($"{i.Key.Year} - { i.Key.Month }");

    foreach(var item in i.Itens)
    {
        WriteLine($"\t{item.Nome}");
    }

    WriteLine("\n");
}

using System;
using System.Linq;
using System.Collections.Generic;
using static System.Console;

public class Program
{
    internal static void MetodoFacil()
    {
        var grupo1 = listaEventos.GroupBy(c => c.Data.ToString("MM/yyyy"))
                                  .Select(g => new { Key = g.Key, Itens = g.ToList() });

        foreach(var i in grupo1)
        {
            WriteLine(i.Key);

            foreach(var item in i.Itens)
            {
                WriteLine($"\t{item.Nome}");
            }

            WriteLine("\n");
        }
    }

    internal static void MetodoComplicado()
    {
        var grupo2 = listaEventos.GroupBy(c => c.Data.Year)
                                 .Select(g => new 
                                 { 
                                     Ano = g.Key, 
                                     Meses = g.ToList()
                                              .GroupBy(c => c.Data.ToString("MMMM"))
                                              .Select(grp => new 
                                                             { 
                                                                 Mes = grp.Key, 
                                                                 Eventos = grp.ToList() 
                                                             })
                                 });

        foreach(var i in grupo2)
        {
            WriteLine($"Ano: {i.Ano}");

            foreach(var mes in i.Meses)
            {
                WriteLine($"\tMês: {mes.Mes}");

                foreach(var evento in mes.Eventos)
                {
                    WriteLine($"\t\t{evento.Nome}");
                }

                WriteLine("\n");
            }           
        }
    }

    public static void Main()
    {           
        MetodoFacil();      
        MetodoComplicado();
    }

    internal static List<Evento> listaEventos = new List<Evento>
    {
        new Evento { Nome = "Evento 1", Data = new DateTime(2015, 01, 01) },
        new Evento { Nome = "Evento 2", Data = new DateTime(2016, 01, 01) },
        new Evento { Nome = "Evento 3", Data = new DateTime(2016, 01, 22) },
        new Evento { Nome = "Evento 4", Data = new DateTime(2016, 02, 24) },
        new Evento { Nome = "Evento 5", Data = new DateTime(2016, 03, 30) },
        new Evento { Nome = "Evento 6", Data = new DateTime(2016, 04, 04) },
        new Evento { Nome = "Evento 7", Data = new DateTime(2017, 01, 01) },
        new Evento { Nome = "Evento 8", Data = new DateTime(2017, 09, 30) },
        new Evento { Nome = "Evento 9", Data = new DateTime(2018, 05, 12) },
    };
}

public class Evento
{
    public string Nome { get; set; }
    public DateTime Data { get; set; }  
}

See working on . NET Fiddle | Code on Github for future reference

7

Everything will depend on how and where you will use, emitting in a console application as a way of understanding the that’s how it is:

var items = listaDeEventos.GroupBy(x => new {x.Data.Year, x.Data.Month}) 
    .Select(x => new
    {
        x.Key, 
        Eventos = x.Select(a => new
        {
            a.Evento
        })
    })                        
    .ToList();                 

foreach(var item in items)
{
    System.Console.WriteLine("{0} / {1}", item.Key.Year, item.Key.Month);
    foreach(var str in item.Eventos)
    {
        System.Console.WriteLine("{0}", str);
    }
    System.Console.WriteLine("-----------------------------");
}

Exit:

2016 / 1
{ Evento = Event1 }
{ Evento = Event2 }
-----------------------------
2016 / 2
{ Evento = Event3 }
{ Evento = Event4 }
-----------------------------
2016 / 3
{ Evento = Event5 }
-----------------------------

The layout is your way, but this way it is easy to understand how something else works as it was not specified the name of the description field I use Evento generating the list of Eventos, and that name has to be your of your consultation.

Another way to use it would be to create Viewmodel of this new type of data:

Class EventosModelView

public class EventosModelView
{
    public int Year { get; set; }
    public int Month { get; set; }         
    public string YearAndMonth
    {
        get
        {
            return string.Format("{0} / {1}", Year, Month);
        }
    }
    public IEnumerable<Events> Events { get; set; }
}

IList<EventosModelView> items = listaDeEventos
                .GroupBy(x => new {x.Data.Year, x.Data.Month}) 
                .Select(x => new EventosModelView
                {
                    Year = x.Key.Year,
                    Month = x.Key.Month,
                    Events = x.Select(s => s)
                })                        
                .ToList();                 

foreach(var item in items)
{
    System.Console.WriteLine("{0}", item.YearAndMonth);
    foreach (var str in item.Events)
    {
        System.Console.WriteLine("{0} {1}", str.Evento, str.Data);
    }
    System.Console.WriteLine("-----------------------------");
}

is the best way to pass information to the View.

References

Browser other questions tagged

You are not signed in. Login or sign up in order to post.