Basically, there are two ways to do this.
The complicated way, where it is necessary to make a grouping by year and another month, this second one being within the first ok, nor even so complicated ).
And also the easy way, which would be to group directly by month and by year, together, that is, concatenate year month in a way that they are unique keys to the grouping.
If you need to maintain a hierarchy (event -> month -> year), use the complicated form. Otherwise, I do not see why not use the simplest form.
The code at the end of the post has an example of each of the two forms.
It is also possible to make a "double" grouping, as you showed in the question, just to illustrate, it would look like this:
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 in GitHub for future reference