0

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?

Tom Gullen
  • 61,249
  • 84
  • 283
  • 456
  • You could implement that `Compare()` as `return compareDate.CompareTo(fromDate);` - but at that point, why would you need it? It just repeats what `DateTime.CompareTo()` already does. – Matthew Watson Oct 27 '21 at 12:58

2 Answers2

1

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.

IMil
  • 1,391
  • 13
  • 17
1

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;
}
Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • This returns the first index where the dates are equal, but he wants the fist where it's greater – Tim Schmelter Oct 27 '21 at 13:19
  • @TimSchmelter Is that what OP wanted? I understood the question wrong then :( But somehow they still accepted – Sweeper Oct 27 '21 at 13:21
  • Just check what `BinarySearch` actually returns. It does not just return "first index where dates are equal". – Evk Oct 27 '21 at 13:22
  • @Sweeper: well, look at it's title :D – Tim Schmelter Oct 27 '21 at 13:22
  • @TimSchmelter I reread the question again. In the first comment, you mean he wants the first where **fromDate** is greater _than the element at that index, not the other way round, right? (because otherwise it's a simple check of the first element) – Sweeper Oct 27 '21 at 13:42