Vincent
Vincent

Reputation: 103

Linq Overlapped date range checking in single collection

Class TimeRange{
  private DateTime StartDate{get; set;}
  private DateTime EndDate{get; set;}
}

List<TimeRange> TimeRangeList = new List<TimeRange>(){
  new TimeRange(){StartDate = new DateTime(2050, 1, 1), 
                    EndDate = new DateTime(2050, 1, 10)},
  new TimeRange(){StartDate = new DateTime(2050, 2, 1), 
                    EndDate = new DateTime(2050, 2, 10)},
  //This item will triggered the overlap validation failed
  new TimeRange(){StartDate = new DateTime(2050, 1, 5),
                    EndDate = new DateTime(2050, 1, 9)},
                              },
}

so after I checked out the similar topic, I still can't figured out the algorithm of checking the overlapped date range.

This is quite simple in SQL, according to Checking for date overlap across multiple date range objects

I just need to compare two date range like this

SELECT COUNT(*)
FROM Table1
WHERE Table1.StartDate < 'endCheckDate'
AND Table1.EndDate > 'startCheckDate'

I found it is difficult to do in Linq, how do we compare all items in one collection within? of cause we can use foreach in just loop the collection just like comparing two list, but how is it work in select?

actually I'm doing something like this

for (int i = 0; i < TimeRangeList .Count(); ++i)
{
        var item = TimeRangeList[i];                    
        for (int y = i + 1; y < TimeRangeList.Count(); ++y)
        {
                var item2 = TimeRangeList[y];

                if (IsOverLapped(item, item2))
                {
                    // this is overlapped
                };
        }
}

private bool IsOverLapped(dynamic firstObj, dynamic secondObj)
{
        return secondObj.StartDate <= firstObj.EndDate && firstObj.StartDate <= secondObj.EndDate;
}

Is there a more elegant way to do without looping?

so my questions is how do we compare one single list for each items itself by linq?

Upvotes: 1

Views: 3413

Answers (2)

Harald Coppoolse
Harald Coppoolse

Reputation: 30464

If I look at your SQLcode, it seems that you have a Table1 object which is a sequence of similar objects, let's say of class Table1Row. Every Table1Row has at least two DateTime properties, a StartDate and an EndDate. Furthermore you have two DateTime objects: startCheckDate and endCheckDate.

You want to count all elements in your Table1 that have a StartDate smaller than startCheckDate and an EndDate larger than endCheckDate

Written as an extension function of IQueryable:

public static int CountOverlapping(this IQueryable<Table1Row> table1,
    DateTime startCheckDate,
    DateTime endCheckDate)
{
    return table1
        .Where (row => row.StartDate < startCheckDate && row.EndDate > endCheckDate)
        .Count();
}

Usage:

DateTime startCheckDate = ...
DateTime endCheckDate = ...
IQueryable<Table1Row> table1 = ...
int nrOfOverlapping = table1.CountOverlapping(startCheckDate, endCheckDate);

Simple comme bonjour?

Upvotes: 0

bommelding
bommelding

Reputation: 3037

A simple brute force idea:

bool overlap = TimeRangeList
    .Any(r => TimeRangeList
         .Where(q => q != r)             
         .Any(q => q.EndDate >= r.StartDate && q.StartDate <= r.EndDate) );

Upvotes: 2

Related Questions