Search code examples
c#linq

How to apply a Value to a List of objects where the Value changes every 7 entries in the List?


I have a object, for the purposes of this example, it is quite simple:

public class DateEntry {
  public DateOnly Date { get; set; }
  public int WeekNumber { get; set; }
}

I get back a List of 42 instances of the DateEntry object.

The Date field gets filled in automatically. What I need to do, is for each 7 of these objects, I need to increment the WeekNumber by 1. This is not the WeekOfYear it is just a requirement by our UI that the first week is 1, second week is 2 all the way to 6 (just like the weeks shown in a single month of any calendar.)

I know I can do this for loops, but would like to do it with LINQ.

I have a similar method that would break it into a list of lists, each inner list having 7 entries in it. But I really want to just modify the original list and have the WeekNumber reflect which of the 6 weeks it is in. I just could not wrap my head around how to alter the following method.

public static List<WeekOfDateEntries> SplitIntoWeeks(this List<DateEntry>? source)
{
  var weekIndex = 1;

  if (source is null || source.Count == 0)
    return [];

  return source
    .Select((x, i) => new { Index = i, Value = x })
    .GroupBy(x => x.Index / 7)
    .Select(x => new WeekOfDateEntries
    {
      WeekNumber = weekIndex++,
      Dates = x.Select(v => v.Date).ToList()
    })
    .ToList();
}

Answer

With a minor tweak, @harald-coppoolse answer was correct. I just had to swap the index position.

return source
  .Select((dateEntry, index) => new TimeEntryRecord
  {
     Date = dateEntry.Date,
     WeekNumber = index / 7 + 1,
   })
  .ToList();

Solution

  • Usually jotting down your requirements will help you with your LINQ statements.

    Requirement

    Input: an enumerable sequence of DateEntries.

    Output a sequence of DateEntries with the same length, with the same values of property Date, in the same order, but with a value of property WeekNumber according to the following defintion:

    WeekNumber of DateEntry[i] in the input sequence == i/7 + 1

    So DateEntry[0] to DateEntry[6] will have WeekNumber 1; DateEntry[7] to DateEntry[13] will have WeekNumber 2, etc.

    How about this:

    IEnumerable<DateEntry> inputDateEntries = ...
    IEnumerable<DateEntry> outputDateEntries = inputDateEntries
        .Select( (index, dateEntry) => new DateEntry
            {
                Date = DateEntry.Date,
                WeekNumber = index / 7 + 1,
            });