44

I have a list of events, each of which has a datetime property. I need to split the list up into sublists by year. The trick is, my list of events is pulled from a database and subject to change, so I can't just hardcode the set of years and sort the events into the right year. Is there a way that I can split my main list of events into sublists so that within each sublist, each event has the same year? So I would end up with a sublist of all 2010 events, a sublist of all 2011 events, and so on.

My list is created like this :

foreach (var ev in eventResults)
    {
        eventsList.Add(new Event()
        {
            Name = ev.Title,
            Month = CultureInfo.CurrentCulture.DateTimeFormat.GetAbbreviatedMonthName(ev.StartDate.Month),
            Day = ev.StartDate.Day,
            Year = ev.StartDate.Year
        });
    }
Bassie
  • 9,529
  • 8
  • 68
  • 159
Erica Stockwell-Alpert
  • 4,624
  • 10
  • 63
  • 130

2 Answers2

71

You need to make a grouping by year like this:

eventsList.GroupBy(x => x.Year)

So later you will be able to iterate through result of code above:

foreach (var eventsInYear in eventsList.GroupBy(x => x.Year))
{
    // eventsInYear.Key - year
    // eventsInYear - collection of events in that year
}
Sean Sailer
  • 343
  • 1
  • 12
Vladimirs
  • 8,232
  • 4
  • 43
  • 79
  • 7
    This is incredibly useful. Just fell in love with C# again. – Ryan Hayes May 14 '18 at 18:16
  • 3
    After grouping, how would you make separate lists based on the year? – Ken Gordon Aug 06 '19 at 18:55
  • 1
    @KenGordon `GroupBy` returns `IEnumerable>`, since `IGrouping` implements `IEnumerable`, you can simply call `ToList` on each individual item. However I do not quite understand why you need that, the purpose of `IGrouping` is to provide a reference to a grouping key (Year). If you don't like `IGrouping` you could reorganise it into `IDictionary`. If you declare `var dict = new Dictionary>();` outside `foreach` loop, then you can populate it by calling `dict.Add(eventsInYear.Key, eventsInYear.ToList());` – Vladimirs Aug 07 '19 at 10:51
  • 1
    @Vladimirs This is somewhat new to me and I wanted to see how to separate parts of a list into separate lists, such as if you wanted 3 lists containing three years. Does that make any more sense? – Ken Gordon Aug 07 '19 at 15:52
  • 3
    @Ken here you go `var year2000 = eventsList.GroupBy(x => x.Year).FirstOrDefault(x => x.Key == 2000).ToList(); var year2001 = eventsList.GroupBy(x => x.Year).FirstOrDefault(x => x.Key == 2001).ToList(); var year2002 = eventsList.GroupBy(x => x.Year).FirstOrDefault(x => x.Key == 2002).ToList();` – Vladimirs Aug 08 '19 at 15:37
  • 1
    @Vladimirs Thanks so much!! – Ken Gordon Aug 09 '19 at 18:56
12

Use GroupBy:

var eventsByYear = eventsList.GroupBy(a => a.Year);

You can then iterate through that collection to process each year:

foreach (var yearEvents in eventsByYear) 
{
    // yearEvents contains all the events for one particular year
    Console.WriteLine("Events for year: " + yearEvents.Key);
    foreach (var e in yearEvents) 
    {
        Console.WriteLine(e);
    }
}
Matt Burland
  • 44,552
  • 18
  • 99
  • 171