4

I am trying to do a query to an IEnumerable<Object> to group by week, for example:

Project(Name, DateStart,ID)

I have IEnumerable<Project> and I want to do a report, grouping by week.

For exmaple:

Week 1
 Project1  8/4/2013 ID1
 Project2  9/4/2013 ID2
Week 2
 Project1  16/4/2013 ID3
 Project2  18/4/2013 ID5
Week 3
 Project1  24/4/2013 ID7
 Project2  26/4/2013 ID8

Please if someone can give me a hand I really appreciate it! I was trying to do a lambda expression but without success.

Thanks!

Marc
  • 3,683
  • 8
  • 34
  • 48
user2112420
  • 955
  • 5
  • 11
  • 26

6 Answers6

14
var weekGroups = projects
    .Select(p => new 
    { 
        Project = p, 
        Year = p.DateStart.Year, 
        Week =  CultureInfo.InvariantCulture.Calendar.GetWeekOfYear
                      (p.DateStart, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday)
    })
    .GroupBy(x => new { x.Year, x.Week })
    .Select((g, i) => new 
    { 
        WeekGroup = g, 
        WeekNum = i + 1,
        Year = g.Key.Year,
        CalendarWeek = g.Key.Week
    });

foreach (var projGroup in weekGroups)
{
    Console.WriteLine("Week " + projGroup.WeekNum);
    foreach(var proj in projGroup.WeekGroup)
        Console.WriteLine("{0} {1} {2}", 
            proj.Project.Name, 
            proj.Project.DateStart.ToString("d"), 
            proj.Project.ID);
}
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • This is genius, this logic worked beautifully for me as well. I had a guy working on it for quite a few hours.. – Code Monkey Jun 10 '13 at 02:36
  • +1 and even referred this questioner (http://stackoverflow.com/questions/20689149/split-last-2-weeks-of-data-into-current-and-previous-week/20689877#20689877) to view this solution. looks nice – jim tollan Dec 19 '13 at 19:25
  • Thanks. +1 This is a really easy to understand, and working example of fairly complex grouping with Linq. Will be coming back to look it up again, and again until its burned into my brain. – Piotr Kula Mar 27 '15 at 16:08
1

You will need to define a function that can determine which week a date is in:

int GetWeek(DateTime date) { ... }

Then the LINQ query to group is:

IEnumerable<IGrouping<int, Project>> groupedProjects = 
         myListOfProjects.GroupBy(p => GetWeek(p.DateStart));

You can iterate over the grouped projects list:

foreach (var weekGroup in groupedProjects)
{
    int week = weekGroup.Key;
    foreach (var project in weekGroup)
    {
        Console.WriteLine("Week " + week + " | Project: " + project.ID);
    }
}
Alex
  • 7,639
  • 3
  • 45
  • 58
0

I think to simplify this task you can add WeekNumber property into Project class and fill it when you are creating object of Project after you can easy group by WeekNumber property

Project(Name, DateStart,ID,WeekNumber)
Sergey K
  • 4,071
  • 2
  • 23
  • 34
0

You can use the GetWeekOfMonth extension posted here:

and then do something like:

        var groups = projects.GroupBy(p => p.Start.GetWeekOfMonth());

        foreach (var group in groups)
        {
            Console.WriteLine("Week {0}", group.Key);
            foreach (var project in group)
            {
                Console.WriteLine("\t{0} | {1:dd/MM/yyyy} | {2}", 
                     project.Name, project.Start, project.Id);
            }
        }
Community
  • 1
  • 1
Juan Ayala
  • 3,388
  • 2
  • 19
  • 24
0

I think just a simple projection will suffice:

// we'll just use the existing settings on the box.
DateTimeFormatInfo dfi = DateTimeFormatInfo.CurrentInfo;
var cal = dfi.Calendar;

var Projects = GetProjectsFromSomewhere(); // assuming IEnumerable<Project>

int week = 1; // this *could* be changed and projected in the Select instead.
foreach (var wg in from p in Projects
    group p by cal.GetWeekOfYear(
        p.StartDate, dfi.CalendarWeekRule, dfi.FirstDayOfWeek))
{
    Console.WriteLine("Week {0}", week);

    foreach (var p in wg)
    {
        Console.WriteLine("    {0} {1} {2}", p.Name, p.StartDate, p.ID);
    }
    week++;
}
code4life
  • 15,655
  • 7
  • 50
  • 82
0

In addition to Tim Schmelter's answer you can get the date of the first day in the week then group by that date.

To get the date of the first day in the week. you can use this code:

public static class DateTimeExtensions
{
    public static DateTime StartOfWeek(this DateTime dt, DayOfWeek startOfWeek)
    {
        int diff = dt.DayOfWeek - startOfWeek;
        if (diff < 0)
        {
            diff += 7;
        }
        return dt.AddDays(-1 * diff).Date;
    }
}

then you can group by the first date of the week like this:

var weekGroups = projects
    .Select(p => new 
    { 
        Project = p
    })
    .GroupBy(x => x.Project.DateStart.StartOfWeek(DayOfWeek.Monday))
    .Select((g, i) => new 
    { 
        WeekGroup = g, 
        WeekNum = i + 1
    });

foreach (var projGroup in weekGroups)
{
    Console.WriteLine("Week " + projGroup.WeekNum);
    foreach(var proj in projGroup.WeekGroup)
        Console.WriteLine("{0} {1} {2}", 
            proj.Project.Name, 
            proj.Project.DateStart.ToString("d"), 
            proj.Project.ID);
} 
hoss77
  • 375
  • 3
  • 9