Re: [CodeJam] UpperBound/LowerBound - оно чего вообще делает?
От: Lexey Россия  
Дата: 18.04.16 20:31
Оценка: 69 (1)
Здравствуйте, 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.
"Будь достоин победы" (c) 8th Wizard's rule.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.