Search code examples
c#linq

change sorted date range time to other date range list in c#


I have this view model that is a List containing StartDate and EndDate. I want to change this range list so if the difference in days between the next start and erevious end date is 1, merge the two ranges into each other.

For example, give this data:


2024/03/21-2024/03/22
2024/03/23-2024/03/25
2024/03/26-2024/03/28
2024/04/01-2024/04/02

I want change to see this result:

2024/03/21-2024/03/28
2024/04/01-2024/04/02

I have this code that runs, but too slowly:

var count = datas.Count();
for (int i = 0; i < count; i++)               
{
    TimeSpan def =(datas[i + 1].StartDate-datas[i].EndDate);
    int diff = int.Parse(def.ToString());
    if ((int)diff == 1)
        datas[i].EndDate=datas[i + 1].EndDate;
}

How can I improve it?


Solution

  • It looks like you have a datas list of an object with two DateTime properties, but we don't know the name of the type of this object. For this purpose, I will pretend the type name is Range.

    For simplicity, I will also assume the input always has at least one item. Finally, I will assume (based on the prior attempted question) that the Range objects in your collection are already sorted in order.

    Given that information, we can process it with this method:

    IEnumerable<Range> Consolidate(IEnumerable<Range> input)
    {
        Range buffer = input.First();
        DateTime border = buffer.EndDate.AddDays(1);
    
        foreach(var r in input.Skip(1))
        {      
            if (r.StartDate <= border)
            {
               // it's part of the same range
               buffer.EndDate = r.EndDate;
            }
            else 
            {
                // it's a new range
                yield return buffer;
                buffer = r;
            }
            border = buffer.EndDate.AddDays(1);
        }
        yield return buffer;
    }
    

    which you would call like this:

    var datas = Consolidate(datas).ToList();
    

    Note, this code can also work if datas is an array or other IEnumerable<Range> by just changing the ToList() call at the end. Additionally, avoiding ToList() and friends can significantly improve memory use and execution time.

    See it work here:

    https://dotnetfiddle.net/2H1Hl2