Diferença entre '..' (ponto duplo) e '…' (ponto triplo) na geração do intervalo?

111

Acabei de começar a aprender Ruby e Ruby on Rails e me deparei com um código de validação que usa intervalos:

validates_inclusion_of :age, :in => 21..99
validates_exclusion_of :age, :in => 0...21, :message => "Sorry, you must be over 21"

A princípio, pensei que a diferença estava na inclusão de endpoints, mas nos documentos da API que examinei, não parecia importar se era .. ou ...: sempre incluía os endpoints.

No entanto, fiz alguns testes no irb e pareceu indicar que ..inclui ambos os pontos de extremidade, enquanto ...incluía apenas o limite inferior, mas não o superior. Isso está correto?

juil
fonte

Respostas:

157

A documentação para Range diz o seguinte:

Faixas construídas usando ..run do início ao fim inclusive. Aqueles criados usando ...excluem o valor final.

Então a..bé semelhante a <= x <= b, enquanto a...bé semelhante a <= x < b.


Observe que, embora to_aem um intervalo de inteiros forneça uma coleção de inteiros, um intervalo não é um conjunto de valores, mas simplesmente um par de valores inicial / final:

(1..5).include?(5)           #=> true
(1...5).include?(5)          #=> false

(1..4).include?(4.1)         #=> false
(1...5).include?(4.1)        #=> true
(1..4).to_a == (1...5).to_a  #=> true
(1..4) == (1...5)            #=> false


Os documentos não incluíam isso, em vez disso exigiam a leitura da seção de Pickaxe sobre Ranges . Obrigado a @MarkAmery ( veja abaixo ) por notar esta atualização.

Andrew Marshall
fonte
11
Exemplo melhor / menos confuso do que o anterior: (1..10).include? 10 #=> truee(1...10).include? 10 #=> false
timmcliu
@timmcliu Embora não seja relevante para ilustrar o ponto que, (a..b) != (a...(b+1))apesar de suas representações de array serem iguais (quando a, b ∈ ℤ). Eu atualizei minha resposta um pouco para expandir isso.
Andrew Marshall
Se Range não é um conjunto de valores, então por que este trecho de código trata Range como um conjunto de valores: (1..5) .inject {| sum, n | soma + n}
VaVa
2
@ValentinVassilev Range não é um conjunto de valores, mas pode gerá-los. injectvem de Enumerableque Rangeinclui; Enumerableutiliza #each, que Rangeimplementa . A lista gerada por Range#eachnunca está contida no Rangepróprio objeto.
Andrew Marshall
6

Está correto.

1.9.3p0 :005 > (1...10).to_a
 => [1, 2, 3, 4, 5, 6, 7, 8, 9]
1.9.3p0 :006 > (1..10).to_a
 => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

A sintaxe de ponto triplo é menos comum, mas é melhor do que (1..10-1).to_a

Chris Heald
fonte
12
Acho realmente bizarro que mais pontos signifiquem que o intervalo representa menos valores. Eu acho que é só isso.. é mais comum e, portanto, menos é preferido para isso?
Andrew Marshall
2
@Andrew: Eu também pensei isso, mas talvez seja porque a variedade de dois pontos é mais comumente desejada e, portanto, mais curta para digitar?
cópia de segurança de
1
Além disso, observe que (a..b-1) != (a...b), embora essa resposta implique que sim.
Andrew Marshall
1
(a..b-1) == (a ... b) somente no caso em que a e b são inteiros e você enumera os intervalos em matrizes. Considere o intervalo (1,0 ... 3,5) - qual é o valor imediatamente anterior a 3,5? Certamente não 2,5!
Chris Heald
3

Os documentos da API agora descrevem esse comportamento:

Faixas construídas usando ..run do início ao fim inclusive. Aqueles criados usando ...excluem o valor final.

- http://ruby-doc.org/core-2.1.3/Range.html

Em outras palavras:

2.1.3 :001 > ('a'...'d').to_a
 => ["a", "b", "c"] 
2.1.3 :002 > ('a'..'d').to_a
 => ["a", "b", "c", "d"] 
Mark Amery
fonte
1

a...b exclui o valor final, enquanto a..b inclui o valor final.

Ao trabalhar com inteiros, a...bse comporta como a..b-1.

>> (-1...3).to_a
=> [-1, 0, 1, 2]

>> (-1..2).to_a
=> [-1, 0, 1, 2]

>> (-1..2).to_a == (-1...3).to_a
=> true

Mas realmente os intervalos diferem em uma reta de número real .

>> (-1..2) == (-1...3)
=> false

Você pode ver isso ao incrementar em etapas fracionárias.

>> (-1..2).step(0.5).to_a
=> [-1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0]

>> (-1...3).step(0.5).to_a
=> [-1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0, 2.5]
Dennis
fonte
1
Ainda incorreto após a edição. Mesmo se a& bforem inteiros, os intervalos são diferentes. Somente quando cada um é convertido em uma matriz eles são iguais. Existe um contra-exemplo específico na resposta aceita.
Andrew Marshall
2
@AndrewMarshall O que eu quis dizer com esse exemplo (mas não muito bem, evidentemente) é em uma escala inteira que se comporta dessa maneira. Esse não é o caso em uma escala fracionária mais precisa, conforme apontado em sua resposta. Acho que os intervalos são usados ​​com mais frequência em uma escala inteira, por isso acredito que essa explicação seja útil.
Dennis
-4

.. e ... denotam um intervalo.

Basta ver no irb:

ruby-1.9.2-p290 :032 > (1...2).each do puts "p" end
p
 => 1...2 
ruby-1.9.2-p290 :033 > (1..2).each do puts "p" end
p
p
Daniel
fonte
2
Mas não responde realmente à pergunta; ambos são descritos como intervalos. Gama inclusiva vs exclusiva .
Craig Ringer