Re[3]: [CodeJam] UpperBound/LowerBound - оно чего вообще делает?
От: Lexey Россия  
Дата: 22.04.16 21:04
Оценка: 69 (1)
Здравствуйте, Sinix, Вы писали:

S>1.

S>Для *Bound нужно написать примеры использования, лучше всего оформлять их в виде тестов.
S>Почему это важно:
S>В дотнете API стараются оформлять так, чтобы его можно было использовать без чтения документации. Любой другой вариант резко уменьшает число пользователей, отсылки к STL тут не помогут, т.к. у подавляющего большинства дотнетчиков опыта работы с c++ — мизер.

ОК. Примеры добавлю в тесты.

S>* BinarySearchLower/BinarySearchUpper? Практически идеал, т.к. ещё и показывает, что нам нужно отсортировать список перед использованием.


Хороший вариант, ИМХО.

S>2.

S>Если мы решаем не трогать имена методов, то у нас такая ситуация: вперемешку с обычными бери-и-пользуйся методами лежат методы, которые надо изучать перед тем, как использовать. Как минимум из-за необходимости сортировать данные и неочевидной пары up-to.

S>Решить легко: вытаскиваем все *Bound-методы в отдельный тип, скажем, в BinarySearchExtenstions — вуаля.


Тоже вариант.

S>3.

S>Мне отчаянно не нравится пара up-to. Её или переименовать в startIndex+endIndex и сделать endIndex < count, или поменять на традиционный дотнетовский startIndex + count.
S>Чтобы принять решение надо бы написать реальный пример использования с этими параметрами и посмотреть, что будет лучше. Возьмёшься? Я могу придумать только такие, где вариант с startIndex + count выигрывает.

Вот тебе пример реального использования:
    //(1)
    var vBegin = verticals.LowerBound(horizontal.Begin, (x, v) => Comparer<double>.Default.Compare(x.Key, v));
    if (vBegin == verticalsCount)
    {
        continue;
    }

    //(2)
    var vEnd = verticals.UpperBound(horizontal.End, vBegin, verticalsCount, (x, v) => Comparer<double>.Default.Compare(x.Key, v));

    //(3)
    for (var vIndex = vBegin; vIndex < vEnd; ++vIndex)


В приниципе, можно тут передавать count вместо endIndex, но, тогда придется перед (2) добавить вычисления нужного count (тогда как endIndex мы и так уже знаем). Плюс, в самой реализации делать обратное преобразование.
Хотя, тут пример не самый удачный, ибо взят еще с той версии, когда не было перегрузки, принимающей только start без end'а.
С другой стороны, в нем видно, что может понадобиться сравнивать результат с endIndex (как в (1)), соответственно, если передавать count, то в итоге получится, что нужно работать с двумя сущностями (и count и endIndex), а не с одной (endIndex).
В общем, КМК, вариант с endIndex более консистентен.
Впрочем, если у нас будут удобные диапазоны, то можно сделать 2 варианта:
1) с start и count;
2) с диапазоном

S>4.

S>Возвращаемое значение.
S>Или оставляем как есть, или, если значение не найдено, возвращаем bitwise complement к индексу, как это делает BinarySearch. Второй вариант явно не подходит для UpperBound, там по определению не может быть "не найдено". Оставляем как есть?

Тут я бы предпочел не менять. Ибо результаты lower/upper, как правило, далее используется в последующих вызовах lower/upper (как в (2)) или цикле (как в (3)). И проверки на дополнения и их снятие тут будут выглядеть лишними.

S>5.

S>Тип параметра. В идеале, надо бы сделать IReadOnlyList, но там столько возни, что я бы отложил до лучших времён.
S>Пример возни см в DictionaryExtensions.GetValueOrDefault. По три перегрузки на каждый метод — нафиг-нафиг.

Угу, кто-то (rameel, вроде) это уже предлагал. Идея хорошая, но с перегрузками будет морока.

S>P.S.

S>С DisjointSets давай разберёмся после того, как добьём Lower/UpperBound()

ОК.
"Будь достоин победы" (c) 8th Wizard's rule.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.