Los rangos representan un intervalo entre dos valores.
Los tipos más comunes que admiten rangos son Integer y String.
Se pueden usar para muchas cosas, como crear una colección rápidamente, cortar strings, comprobar si un valor está dentro de un rango e iterar.
Se crean con el operador de rango .. o ... (inclusivo y exclusivo, respectivamente).
1..5 # => 1..5
1...5 # => 1...5
(1..5).to_a # => [1, 2, 3, 4, 5]
(1...5).to_a # => [1, 2, 3, 4]
La razón de tener dos operadores de rango es permitir crear rangos que incluyan o excluyan el valor final, lo cual puede ser útil cuando, por ejemplo, trabajas con índices que empiezan en cero.
Los rangos también se pueden crear con el inicializador de Range.
Range.new(1, 5) # A range containing 1, 2, 3, 4, 5
Cuando creas un rango en Ruby con los operadores de rango .. o ... y quieres llamar a un método sobre el rango, debes envolver el rango entre paréntesis.
Esto se debe a que, de lo contrario, el método se llamará sobre el segundo argumento del operador de rango.
(1..5).sum # => 15
1..5.sum # => Error: undefined method `sum' for 5:Integer (NoMethodError)
Cuando quieres cortar un string, puedes usar el operador de rango para obtener una subcadena. Es decir, creando un rango con el índice inicial y final de la subcadena.
"Hello World"[0..4] # => "Hello"
"Hello World"[6..10] # => "World"
También puedes usar índices negativos para obtener la subcadena desde el final del string.
"Hello World"[-5..-1] # => "World"
"Hello World"[6..-4] # => "Wo"
Los rangos tienen un conjunto de métodos que puedes usar para trabajar con ellos. Por ejemplo, estos métodos sirven para obtener la suma de todos los valores del rango o para comprobar si el rango incluye un valor.
| Método | Descripción | Ejemplo |
|---|---|---|
sum |
Devuelve la suma de todos los valores del rango | (1..5).sum # => 15 |
size |
Devuelve el tamaño del rango | (1..5).size # => 5 |
include? |
Devuelve true si el rango incluye el valor dado; de lo contrario, false
|
(1..5).include?(3) # => true |
Un rango puede no tener fin ni inicio.
En el rango sin fin o sin inicio, el valor inicial o final es nil, pero al definir el rango se puede omitir el nil.
Usar rangos sin inicio y sin fin es útil cuando quieres, por ejemplo, cortar un string desde el principio o hasta el final.
"Hello World"[0..] # => "Hello World"
"Hello World"[4..] # => "o World"
"Hello World"[..5] # => "Hello "
Si no se usa sobre una colección, el rango sin fin puede provocar una secuencia sin fin si no se usa con cuidado.
Los strings también se pueden usar en rangos y permiten obtener un intervalo de strings entre dos strings. Su comportamiento puede ser algo inesperado con ciertos strings, así que úsalo con cuidado.
"aa".."az".to_a # => ["aa", "ab", "ac", ..., "az"]
Ruby te permite usar objetos personalizados en los rangos. Para ello, el objeto debe implementar lo siguiente:
Comparable
succ
<=>
Estos métodos hacen posible que el rango pueda iterar sobre el objeto y comparar los objetos del rango.
class Foo
include Comparable
attr_reader :value
def initialize(value)
@value = value
end
def succ
Foo.new(value + 1)
end
def <=>(other)
value <=> other.value
end
end
(Foo.new(1)..Foo.new(5))
# => #<Foo:0x7f3552bebe70 @value=1>, #<Foo:0x7f3552bebe50 @value=2>, #<Foo:0x7f3552bebe40 @value=3>, #<Foo:0x7f3552bebe30 @value=4>, #<Foo:0x7f3552bebe20 @value=5>