2010-07-29 16 views
8

Digamos que tengo un rango de 0 a 10:¿Hay alguna forma elegante de excluir el primer valor de un rango?

range = 0...10 

tres puntos significan que el último valor (10) está excluido:

range.include? 10 
=> false 

Ahora, hay una manera similar y elegante para excluir el primer valor ?
Para el ejemplo anterior, esto significaría para incluir todos los valores que son más grandes (>, no >=) que 0 y menor de 10.

+0

Creo que excluir el último valor suele ser muy útil, como 'rango = 0 ... algo.size' ¿Cuál es su uso para la necesidad de excluir el primer valor? –

+0

Compruebo si un determinado conjunto de valores está dentro de ese rango. Solo quiero manejar valores cero de manera diferente. Sé cómo lograr esto, pero tenía curiosidad, si hay algo similar como '...' para excluir el * primer * valor de un rango. –

+0

Aprendí más sobre el alcance en 5 minutos que en el último año. ¡Gracias! –

Respuesta

2

((0+1)..10) 
+3

El único problema con esto sería que los valores entre 0 y 1 no se incluirían. Sí, puedes decir '0.00000001..10' (o algo similar, dependiendo de cuántos decimales necesites). Pero eso es bastante feo, IMO, cuando lo que quiero decir es: '0

+4

Desde Ruby 2.2 puede usar '(0.0) .next_float..10.0' – Envek

+0

O, mi sintaxis preferida:' 0.to_f.next_float..10' – Danyel

0

Tal vez podrías crear tu propio tipo de rango

class FancyRange 
    def initialize(minimum, maximum, exclusive_minimum, exclusive_maximum) 
    # insert code here 
    end 

    # insert more code here 

end 
5

Tengo dos sugerencias para usted, no son muy ideales, pero son lo mejor que se me ocurre.

Primero puede definir un nuevo método en la clase Range que hace lo que describe. Se vería así:

class Range 
    def have?(x) 
    if x == self.begin 
     false 
    else 
     include?(x) 
    end 
    end 
end 

p (0..10).have?(0)  #=> false 
p (0..10).have?(0.00001) #=> true 

No sé, acabo de utilizar un sinónimo de "incluir" como un nombre de método, tal vez usted puede pensar en algo mejor. Pero esa es la idea.

Y luego podría hacer algo un poco más elaborado y definir un método en la clase Range que marque un rango como aquel para excluir el valor inicial, y luego cambiar el método include? de Range para verificar esa marca.

class Range 
    def exclude_begin 
    @exclude_begin = true 
    self 
    end 

    alias_method :original_include?, :include? 
    def include?(x) 
    return false if x == self.begin && instance_variable_defined?(:@exclude_begin) 
    original_include?(x) 
    end 

    alias_method :===, :include? 
    alias_method :member?, :include? 
end 

p (0..10).include?(0)      #=> true 
p (0..10).include?(0.00001)    #=> true 
p (0..10).exclude_begin.include?(0)  #=> false 
p (0..10).exclude_begin.include?(0.00001) #=> true 

Una vez más, es posible que desee una mejor (más elegante?) Nombre para el método de exclude_begin, Acabo de elegir que, dado que es consistente con el método de rango exclude_end?.

Edit: Tengo otra para ti, solo porque encuentro este problema tan interesante. : P Esto sólo va a trabajar en la última versión de Ruby 1.9, pero permitirá la siguiente sintaxis:

(0.exclude..10).include? 0  #=> false 
(0.exclude..10).include? 0.00001 #=> true 

Se utiliza la misma idea que mi segunda sugerencia, pero almacena el "marcador de exclusión" en el número en lugar del rango Tengo que usar SimpleDelegator de Ruby 1.9 para lograr esto (los números en sí mismos no pueden tener variables de instancia ni nada), por lo que no funcionará en las versiones anteriores de Ruby.

+0

Wow. Esa es una gran respuesta. ¡Muchas gracias! Todavía estoy ocupado tratando de entender su solución Ruby 1.9. Es genial ver lo que es posible. Sin embargo, creo que la solución más elegante y obvia de la OMI sería describir un rango con la exclusión de los valores de inicio y final en cuatro puntos: '0 .... 10'. Realmente no estoy seguro de si esto es posible incluso sin jugar con el archivo range.c? –

+0

Sí, estoy de acuerdo en que sería una buena sintaxis, pero requeriría un cambio en la gramática de Ruby (causa un error de sintaxis si la escribe). Una cosa que puedes hacer cerca de eso en Ruby 1.9 es usar mi último ejemplo allí, pero llama el método 'call' en lugar de' exclude'. Entonces puedes usar la nueva sintaxis de azúcar de Ruby y escribir '0.() .. 10' y obtener la misma cosa. '0.()' Es un atajo para el método 'call'. Sin embargo, no sé si eso es mejor o no. : P –

+0

Sí, agradable. Pero esto significaría una confusión total, supongo. ;-) Prefiero mantener tus soluciones '(0..10) .exclude_begin' o' 0.exclude..10'. Gracias por tu respuesta otra vez. Aprendí mucho. (Acepté otra respuesta, porque no describiría esto como una solución elegante similar a la notación de tres puntos para excluir el último valor). –

Cuestiones relacionadas