Home > Software engineering >  Using IComparer to get index where DateTime is greater than
Using IComparer to get index where DateTime is greater than

Time:10-27

Given:

List<DateTime> descOrderedDates;

And a datetime:

DateTime fromDate;

I can easily count the number of items where the date is greater than fromDate as follows:

var count = descOrderedDates.Count(c=> c > fromDate);

However I'm struggling to implement this as a BinarySearch:

var ix = descOrderedDates.BinarySearch(fromDate, new CompareDates());

private class CompareDates : IComparer<DateTime>
{
    public int Compare(DateTime compareDate, DateTime fromDate)
    {
        if (fromDate > compareDate) return 1;
        return 0;
    }
}

This keeps returning 1 in a test case where fromDate is less than the smallest date in the list. I'm struggling to wrap my head around IComparer, can anyone tell me what I'm doing wrong?

CodePudding user response:

Your comparer returns 1 in case of fromDate > compareDate, but it should also return -1 in the opposite case, and 0 only if they're equal. And do you need a custom comparer at all? I believe for dates the default comparison will work fine.

CodePudding user response:

You are supposed to return either a negative value, a positive value, or 0 in Compare, depending on whether the parameters are greater than, less than, or equal to each other, as the documentation says. (So your implementation of not returning negative values at all is incorrect.)

You can do that by explicitly writing out the three cases and comparing the dates with < and >, but DateTime has the CompareTo method (as it implements IComparable), so you can just use that instead:

public int Compare(DateTime date1, DateTime date2)
    => date2.CompareTo(date1);

Note that the order of the two dates are reversed when we call CompareTo, to achieve the descending order for the Comparer that we are implementing.

If you want to find the first index of the list with a date that is less than fromDate, you also need to do some checking on ix:

int firstIndexLessThanFromDate;
if (ix < 0) {
    // applying bitwise not gives you where the element should be inserted
    // i.e. the index of the next smallest element
    firstIndexLessThanFromDate = ~ix;
} else {
    firstIndexLessThanFromDate = ix   1;
}
  • Related