Хорошо, скажем, у вас действительно большой диапазон в рубине.Я хочу найти способ получить максимальное значение в диапазоне.
Диапазон является эксклюзивным (определяется тремя точками), что означает, что он не включает конечный объект в свои результаты.Он может состоять из Integer, String, Time или любого другого объекта, который отвечает на #<=>
и #succ
.(которые являются единственными требованиями для начального / конечного объекта в Range)
Вот пример исключительного диапазона:
past = Time.local(2010, 1, 1, 0, 0, 0)
now = Time.now
range = past...now
range.include?(now) # => false
Теперь я знаю, что могу просто сделать что-то подобное, чтобы получитьмаксимальное значение:
range.max # => returns 1 second before "now" using Enumerable#max
Но это займет не тривиальное количество времени для выполнения.Я также знаю, что могу вычесть 1 секунду из того, чем является конечный объект.Однако объект может быть чем-то отличным от времени, и он может даже не поддерживать #-
.Я бы предпочел найти эффективное общее решение, но я хочу объединить код специального случая с откатом к общему решению (подробнее об этом позже).
Как упоминалось выше, использование Range#last
не будет работатьлибо, потому что это исключительный диапазон и не включает в себя последнее значение в своих результатах.
Самый быстрый подход, о котором я мог подумать, был такой:
max = nil
range.each { |value| max = value }
# max now contains nil if the range is empty, or the max value
Это похоже на то, что Enumerable#max
делает (который Range наследует), за исключением того, что он использует тот факт, что каждое значение будет больше, чем предыдущее, поэтому мы можем пропустить, используя #<=>
, чтобы сравнить каждое значение с предыдущим (как Range#max
делает)сэкономив немного времени.
Другой подход, о котором я думал, - это иметь специальный код для общих типов рубинов, таких как Integer, String, Time, Date, DateTime, а затем использовать приведенный выше код в качестве запасного варианта.,Было бы немного некрасиво, но, вероятно, гораздо эффективнее, когда встречались эти типы объектов, потому что я мог бы использовать вычитание из Range#last
, чтобы получить максимальное значение без итерации.
Может кто-нибудь придумать более эффективный/ более быстрый подход, чем этот?