Бинарный поиск возвращает неправильное значение, даже если список отсортирован. Вот список:
1707 ABCD
1707 XXXX
1725 DEFG
1725 HIJK
1725 LMNOP
Я получаю этот список из файла, предварительно настроенного по времени (первый столбец), поэтому я не сортирую это в своем коде. Когда я делаю двоичный поиск на 1725 DEFG, он возвращает мне 1725 LMNOP перед поразрядным дополнением. Если я поразрядное дополнение, результат будет 1725 HIJK.
Почему это?
Здесь реализация:
public class RecComparer: IComparer<MyData>
{
public int Compare(MyData x, MyData y)
{
if (x.DateDetails == null)
{
if (y.DateDetails == null)
{
return 0;
}
else
{
return -1;
}
}
else
{
if (y.DateDetails == null)
{
return 1;
}
else
{
int retval = x.DateDetails.Length.CompareTo(y.DateDetails.Length);
if (retval != 0)
{
return retval;
}
else
{
return x.DateDetails.CompareTo(y.DateDetails);
}
}
}
}
}
Здесь вызов BinarySearch:
lookAhead = recordList.BinarySearch(lookAheadtime, (IComparer<MyData>)rc);
Любая причина, по которой она ведет себя так.
РЕДАКТИРОВАТЬ:
public class MyData
{
public string DateDetails { get; set; }
public string TrackDetails { get; set; }
}
Обновление № 2: двоичный поиск с использованием пользовательского сопоставления в списке с дубликатами.
Предполагая, что в "1707 ABCD", "1707" есть DateDetails
а "ABCD" - это TrackDetails
, у вас есть массив данных с двумя полями, которые уже отсортированы по порядку одного из двух полей, а именно DateDetails
. Таким образом, может быть несколько записей с теми же DateDetails
.
Если вы выполните BinarySearch, он вернет одну из записей с указанными DateDetails
, не обязательно первой. Затем вы должны отсканировать назад, чтобы найти первый.
public static class ListHelper
{
/// <summary>
/// Return the zero-based index of the first matching item in the sorted List,
/// if a match for item is found; otherwise, a negative number that is the bitwise
/// complement of the index of the next element that is larger than item or, if there is
/// no larger element, the bitwise complement of Count.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="list"></param>
/// <param name="item"></param>
/// <param name="comparer"></param>
/// <returns>The zero-based index of the first matching item in the sorted List,
/// if item is found; otherwise, a negative number that is the bitwise complement
/// of the index of the next element that is larger than item or, if there is
/// no larger element, the bitwise complement of Count.</returns>
public static int BinarySearchFirst<T>(this List<T> list, T item, IComparer<T> comparer)
{
int start = list.BinarySearch(item, comparer);
for (; start > 0 && comparer.Compare(list[start], list[start - 1]) == 0; start--)
;
return start;
}
/// <summary>
/// Find the zero-based indices of the first and last matching items in the sorted List,
/// if a match for item is found; otherwise, a negative number for both that is the bitwise
/// complement of the index of the next element that is larger than item or, if there is
/// no larger element, the bitwise complement of Count.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="list"></param>
/// <param name="item"></param>
/// <param name="comparer"></param>
/// <param name="start">The zero-based index of the first matching item in the List,
/// if item is found; otherwise, a negative number that is the bitwise complement
/// of the index of the next element that is larger than item or, if there is
/// no larger element, the bitwise complement of Count.</param>
/// <param name="end">The zero-based index of the first matching item in the sorted List,
/// if item is found; otherwise, a negative number that is the bitwise complement
/// of the index of the next element that is larger than item or, if there is
/// no larger element, the bitwise complement of Count.</param>
/// <returns>true if found, else false</returns>
public static bool BinarySearchRange<T>(this List<T> list, T item, IComparer<T> comparer, out int start, out int end)
{
start = end = list.BinarySearch(item, comparer);
if (start < 0)
return false;
for (; start > 0 && comparer.Compare(list[start], list[start - 1]) == 0; start--)
;
for (int last = list.Count - 1; end < last && comparer.Compare(list[end], list[end + 1]) == 0; end++)
;
return true;
}
}
Я не уверен, понимаю ли я эту проблему, но не можете ли вы просто использовать linq для поиска в списке?
recordList.Where(x=>x.columnName == 1725).First();