使用IComparer对降序DateTime列表二分查找大于指定值的索引问题
问题原因
你当前的实现存在两个核心错误:
- IComparer
的Compare方法返回值不符合规范
Compare(x,y)的返回值必须严格遵循以下规则,BinarySearch才能正常工作:- 返回值 < 0:代表x小于y
- 返回值 = 0:代表x等于y
- 返回值 > 0:代表x大于y
你现有的比较器仅返回1和0两种结果,完全不符合要求,导致BinarySearch无法计算出正确的索引位置。
- 没有适配列表的降序排序规则
.NET内置的List<T>.BinarySearch默认是为升序排列的列表设计的,你的列表是降序排列,比较器的逻辑需要和排序规则保持一致。
修复方案
第一步:实现符合要求的降序比较器
private class DescendingDateTimeComparer : IComparer<DateTime> { public int Compare(DateTime x, DateTime y) { // 降序比较逻辑,和默认升序的CompareTo结果相反即可 return y.CompareTo(x); } }
第二步:正确处理BinarySearch的返回值
BinarySearch的返回值规则:找到匹配项则返回对应索引,未找到则返回负数,对负数做按位取反(~)得到的就是目标值应该插入的位置,这个位置正好等于所有大于fromDate的元素数量。
完整统计代码如下:
var comparer = new DescendingDateTimeComparer(); var searchResult = descOrderedDates.BinarySearch(fromDate, comparer); int count; if (searchResult >= 0) { // 存在和fromDate相等的元素,需要定位到第一个相等元素的索引 // 避免重复相等的日期影响统计结果 while (searchResult > 0 && comparer.Compare(descOrderedDates[searchResult - 1], fromDate) == 0) { searchResult--; } count = searchResult; } else { // 未找到匹配项,按位取反得到插入位置就是大于fromDate的元素个数 count = ~searchResult; }
你之前测试异常的原因
你错误的比较器返回值导致BinarySearch的索引计算完全错乱,当fromDate小于列表最小日期时,本应该返回对应列表长度的计数,却返回了错误的1。
内容的提问来源于stack exchange,提问作者Tom Gullen
相关产品推荐
相关产品推荐

