Здравствуйте, Sinix, Вы писали:
S>Можно пример реального юз-кейза для этой штуки?
Всякая математика, требующая многократных поисков в списке/массиве. У меня в одном из проектов используется для поиска пересечений кластеров на плоскости.
Ну и, в Google Code Jam иногда бывает полезно.
S>Как я понял, ищется индекс вставки для элемента в отсортированном списке, так?
LowerBound — да.
S>Тогда:
S>0. Комментарии
S>S>// Returns the minimum index i in the range [0, list.Count — 1] such that list[i] > value — Upper
S>// Returns the minimum index i in the range [0, list.Count — 1] such that list[i] >= value — Lower
S>Вот фиг из них поймёшь, что имеется в виду. IndexOfFirstGreaterBy/IndexOfFirstGreaterByOrEqual тогда уж
Это стандартные названия этих алгоритмов из STL.
S>1. Проблема с именем, будет путаница с Array.GetUpperBound()
Маловероятно. Array.GetUpperBound() редко используется.
S>2. Путаница с параметром to. В дотнете принято делать пару startIndex + count (сколько элементов просматривать). Аля BinarySearch() / CopyTo() / Substring().
В данном случае это не удобно по 2-м причинам:
1) В оригинале эти алгоритмы работают с итераторами. В таком виде они понятны всем, кто их видел в STLе.
2) Непонятно, что возвращать в случае отсутствия требуемого элемента. -1 — криво, ибо придется всегда отдельно отрабатывать. А
to = start + count прекрасно укладывается в общую арифметику индексов.
S>Ок, допустим неудобно настолько, что мы забиваем на least surprise. Зачем тогда to может быть равен count? это ж индекс типа. Я вот про это:
S>
S> private static void ValidateIndicesRange(int from, int to, int count)
S> {
S> ...
S> Code.AssertArgument(to <= count, nameof(to),
S> "The {0} index should not exceed the {1}", nameof(to), nameof(count));
S> ...
S> }
S>
По факту это не индекс. Это верхняя граница диапазона индексов. То, что в STL зовется
end.
to мне самому не очень нравится, но ничего лучше не придумалось. Можно, попробовать в
upto переименовать, но не уверен, что будет лучше.
Или можно сделать begin/end, как в STLe.
S>3. Проблема с возвращаемым значением. Непонятно, найдено ли точное совпадение, или просто все предыдущие оказались меньше.
Это by design. Если хочется точное совпадение, то делается ровно одно дополнительное сравнение
на list[result] == value
S>4. Выдаёт рандом на неотсортированных списках. Вот это для меня самый главный WTF.
Это бинарный поиск, так что было бы странно, если бы он работал на неотсортированных списках.
S>И собственно вопрос: чем плох стандартный BinarySearch? С учётом стандартного трюка
S>S>var index = Array.BinarySearch(data.BinarySearch(2);
S>if (index < 0)
S>{
S> var insertIndex = ~index;
S> ...
S>}
S>
Тем, что:
1) Только для массивов.
2) Нет аналога UpperBound и EqualRange.
S>UPD и тот же вопрос — для EqualRange. Как часто нам нужен диапазон с-по для одного значения, не для valueFrom-valueTo?
Редко, но бывает. Когда нужно выбрать все значения с заданным "ключем". И, имея Lower/Upper, логично его тоже реализовать по аналогии с STL.
S>UPD2 и для PartitionPoint — тож. Очень неочевидно, что у нас 4 метода по сути делают одно и то же, только с слегка разным поведением при сравнении.
Ну, вот из-за "слегка" разного поведения их и получается 4.