Ok, así que digamos que tiene un Rango muy grande en rubí. Quiero encontrar una manera de obtener el valor máximo en el Rango.La forma más rápida de obtener el máximo valor de un Rango exclusivo en ruby
El rango es exclusivo (se define con tres puntos) lo que significa que no incluye el objeto final en sus resultados. Podría estar formado por Entero, Cadena, Tiempo o realmente cualquier objeto que responda a #<=>
y #succ
. (Que son los únicos requisitos para el objeto de inicio/fin en Rango)
He aquí un ejemplo de una gama exclusiva:
past = Time.local(2010, 1, 1, 0, 0, 0)
now = Time.now
range = past...now
range.include?(now) # => false
Ahora sé que sólo podía hacer algo como esto para obtener el valor máximo:
range.max # => returns 1 second before "now" using Enumerable#max
Pero esto llevará una cantidad de tiempo no trivial para ejecutar. También sé que puedo restar 1 segundo de lo que sea que sea el objeto final. Sin embargo, el objeto puede ser distinto de Time, y es posible que ni siquiera sea compatible con #-
. Preferiría encontrar una solución general eficiente, pero estoy dispuesto a combinar un código de caso especial con una solución general (más sobre esto más adelante).
Como se mencionó anteriormente usando Range#last
tampoco funcionará, porque es un rango exclusivo y no incluye el último valor en sus resultados.
El enfoque más rápido que podía pensar era la siguiente:
max = nil
range.each { |value| max = value }
# max now contains nil if the range is empty, or the max value
Esto es similar a lo que Enumerable#max
hace (que hereda de Campo), excepto que explota el hecho de que cada valor va a ser mayor que la anterior, por lo que podemos omitir el uso de #<=>
para comparar cada valor con el anterior (la forma en que Range#max
lo hace) ahorrando un poco de tiempo.
El otro enfoque en el que estaba pensando era tener un código de caso especial para tipos de rubí comunes como entero, cadena, hora, fecha, fecha y hora, y luego usar el código anterior como alternativa. Sería un poco feo, pero probablemente mucho más eficiente cuando se encuentren esos tipos de objetos porque podría usar la resta desde Range#last
para obtener el valor máximo sin iterar.
¿Alguien puede pensar en un enfoque más eficiente/más rápido que esto?
En su última línea, tiene 'range.last.pred'. Eso no compila para mí. Tampoco lo hace 'range.last.prev'. ¿Podría explicar esa porción? –
Intenta usar 'pred' y si eso falla, prueba' range.last-1' de lo contrario vuelve a una solución diferente –
'pred' se implementa para enteros en las versiones posteriores de Ruby (está ahí en mi 1.8.7- 174, y debería estar allí en 1.9+). No está disponible para todas las clases que implementan 'succ', por lo que puede ser necesario definirlo usted mismo. – molf