範囲生成における「..」(ダブルドット)と「…」(トリプルドット)の違いは?


110

RubyとRuby on Railsの学習を始めたばかりで、範囲を使用する検証コードに出くわしました。

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

最初に私には違いがエンドポイントを含めることにあったと思ったが、私はに見えたAPIドキュメントに、それがあったかどうかは関係していないようでした.....。それは、常にエンドポイントが含まれています。

ただし、irbでいくつかのテストを行ったところ..、両方のエンドポイントが...含まれているが、上限は含まれていないが下限が含まれていることが示されているようです。これは正しいです?

回答:


157

Range ドキュメントには次のように書かれています:

..最初から最後までrunを使用して構築された範囲。を使用...して作成されたものは、終了値を除外します。

だから、a..bのようなものであるa <= x <= bのに対し、a...bのようなものですa <= x < b


to_a整数の範囲では整数のコレクションを提供しますが、範囲は値のセットではなく、単に開始/終了値のペアであることに注意してください:

(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


ドキュメントにはこれが含まれていませんでしたが、範囲のつるはしのセクションを読む必要がありました。この更新に注意してくれた@MarkAmery(下記参照)に感謝します。


11
より良い/より少ない上記以外の例を混乱:(1..10).include? 10 #=> true(1...10).include? 10 #=> false
timmcliu

@timmcliu (a..b) != (a...(b+1))それらの配列表現が等しいにもかかわらず(a、b when whenのとき)の点を説明することには関係ありません。私はそれを拡張するために私の答えを少し更新しました。
アンドリューマーシャル

Rangeが値のセットではない場合、なぜこのコードはRangeを値のセットとして扱うのですか?(1..5).inject {| sum、n | sum + n}
VaVa '25 / 10/25

2
@ValentinVassilev Rangeは値のセットではありませんが、値を生成できます。inject来てEnumerableいるRange含み; Enumerableを利用し#eachRange実装します。によって生成されたリストRange#eachRangeオブジェクト自体に含まれることはありません。
Andrew Marshall

6

それは正しいです。

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]

三重ドット構文はあまり一般的ではありませんが、 (1..10-1).to_a


12
ドットが多いということは、範囲が表す値が少ないことを意味するのは本当に奇妙だと思います。私はそれ..がより一般的であり、したがって、それよりも少ない方が好ましいと思いますか?
Andrew Marshall

2
@Andrew:私もそう思いましたが、多分2ドットの方がより一般的に望まれていて、タイプするのに短いのでしょうか?
safecopy 2012年

1
また、(a..b-1) != (a...b)この回答はそうであると示唆していますが、
アンドリューマーシャル

1
(a..b-1)==(a ... b)aとbが整数で、範囲を配列に列挙する場合のみ。範囲(1.0 ... 3.5)を検討してください-3.5の直前の値は何ですか?確かに2.5ではありません!
Chris Heald、2015

3

APIドキュメントはこの動作を説明します:

..最初から最後までrunを使用して構築された範囲。を使用...して作成されたものは、終了値を除外します。

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

言い換えると:

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

1

a...b 終了値を除外し、終了値をa..b 含めます。

整数を使用する場合、a...bとして動作し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

しかし、実際には範囲は実数線上で異なります。

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

これは、小数ステップで増分するときに確認できます。

>> (-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]

1
編集後もまだ正しくありません。場合でもab整数であり、範囲が異なっています。それぞれが配列に変換された場合のみ、それらは同じです。受け入れられた回答に特定の反例が存在します。
アンドリューマーシャル

2
@AndrewMarshallその例で私が言うつもりだったのは(はっきりとは言えませんが)整数スケールであり、そのように動作します。あなたの答えで指摘されているように、これはより正確な分数スケールの場合には当てはまりません。範囲は整数スケールで使用されることが多いと思います。そのため、このような説明が役立つと思います。
デニス

-4

..および...は範囲を示します。

ちょうどそれを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

2
ただし、実際には質問には答えません。どちらも範囲であると説明されています。包括的 vs 排他的範囲。
クレイグリンガー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.