Sự khác biệt giữa '..' (dấu hai chấm) và '…' (dấu ba chấm) trong tạo phạm vi?


110

Tôi vừa mới bắt đầu học Ruby và Ruby on Rails và bắt gặp mã xác thực sử dụng các phạm vi:

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

Lúc đầu, tôi nghĩ sự khác biệt nằm ở việc bao gồm các điểm cuối, nhưng trong tài liệu API mà tôi đã xem xét, dường như không quan trọng dù nó có ..hay không ...: nó luôn bao gồm các điểm cuối.

Tuy nhiên, tôi đã thực hiện một số thử nghiệm trong irb và nó dường như chỉ ra rằng ..bao gồm cả hai điểm cuối, trong khi ...chỉ bao gồm giới hạn dưới chứ không bao gồm giới hạn trên. Điều này có chính xác?

Câu trả lời:


157

Các tài liệu cho Phạm vi nói điều này:

Phạm vi được xây dựng bằng cách sử dụng ..chạy từ đầu đến cuối hoàn toàn. Những người được tạo bằng cách sử dụng ...loại trừ giá trị cuối cùng.

Như vậy a..blà thích a <= x <= b, ngược lại a...blà như thế a <= x < b.


Lưu ý rằng, trong khi to_atrên một Phạm vi số nguyên cung cấp một tập hợp các số nguyên, một Phạm vi không phải là một tập hợp các giá trị, mà chỉ đơn giản là một cặp giá trị bắt đầu / kết thúc:

(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


Các tài liệu được sử dụng để không bao gồm điều này, thay vào đó yêu cầu đọc phần Cái cuốc trên Rặng . Cảm ơn @MarkAmery ( xem bên dưới ) đã lưu ý đến bản cập nhật này.


11
Tốt hơn / ít khó hiểu ví dụ so với ở trên: (1..10).include? 10 #=> true(1...10).include? 10 #=> false
timmcliu

@timmcliu Mặc dù không liên quan đến việc minh họa điểm (a..b) != (a...(b+1))mặc dù các biểu diễn mảng của chúng bằng nhau (khi a, b ∈ ℤ). Tôi đã cập nhật câu trả lời của mình một chút để mở rộng về điều đó.
Andrew Marshall

Nếu Phạm vi không phải là một tập hợp các giá trị, thì tại sao đoạn mã này lại coi Phạm vi là một tập hợp các giá trị: (1..5) .inject {| sum, n | sum + n}
VaVa

2
@ValentinVassilev Phạm vi không phải là một tập hợp các giá trị, nhưng nó có thể tạo ra chúng. injectxuất phát từ Enumerableđó Rangebao gồm; Enumerablesử dụng #each, Rangethực hiện . Danh sách được tạo bởi Range#eachkhông bao giờ được chứa trong Rangechính đối tượng.
Andrew Marshall

6

Đúng rồi.

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]

Cú pháp ba dấu chấm ít phổ biến hơn, nhưng đẹp hơn (1..10-1).to_a


12
Tôi nghĩ thật kỳ lạ khi nhiều dấu chấm hơn có nghĩa là phạm vi đại diện cho ít giá trị hơn . Tôi đoán nó chỉ ..là phổ biến hơn và do đó ít được ưa thích hơn cho nó?
Andrew Marshall

2
@Andrew: Tôi cũng nghĩ vậy, nhưng có lẽ do loại hai chấm thường được mong muốn hơn và do đó ngắn hơn để nhập?
an toàn

1
Ngoài ra, hãy lưu ý rằng (a..b-1) != (a...b), mặc dù câu trả lời này ngụ ý rằng chúng đúng như vậy.
Andrew Marshall

1
(a..b-1) == (a ... b) chỉ trong trường hợp a và b là các số nguyên và bạn liệt kê các phạm vi thành mảng. Hãy xem xét phạm vi (1,0 ... 3,5) - giá trị ngay trước 3,5 là bao nhiêu? Chắc chắn không phải 2,5!
Chris Heald,

3

Tài liệu API hiện mô tả hành vi này:

Phạm vi được xây dựng bằng cách sử dụng ..chạy từ đầu đến cuối hoàn toàn. Những người được tạo bằng cách sử dụng ...loại trừ giá trị cuối cùng.

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

Nói cách khác:

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 loại trừ giá trị cuối, trong khi a..b bao gồm giá trị cuối cùng.

Khi làm việc với số nguyên, a...bhoạt động như 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

Nhưng thực sự các phạm vi khác nhau trên một đường số thực .

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

Bạn có thể thấy điều này khi tăng dần theo các bước phân số.

>> (-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
Vẫn không chính xác sau khi chỉnh sửa. Ngay cả khi a& blà số nguyên, các phạm vi khác nhau. Chỉ khi mỗi cái được chuyển đổi thành một mảng thì chúng mới giống nhau. Một ví dụ cụ thể tồn tại trong câu trả lời được chấp nhận.
Andrew Marshall

2
@AndrewMarshall Điều tôi muốn nói với ví dụ đó (nhưng không rõ ràng lắm) là trên thang số nguyên, nó hoạt động theo cách đó. Đây không phải là trường hợp trên thang phân số chính xác hơn, như đã chỉ ra trong câu trả lời của bạn. Tôi nghĩ rằng các phạm vi thường được sử dụng nhiều nhất trên thang số nguyên, đó là lý do tại sao tôi tin rằng lời giải thích như vậy là hữu ích.
Dennis

-4

.. và ... biểu thị một phạm vi.

Chỉ cần xem nó trong 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
Tuy nhiên, không thực sự trả lời câu hỏi; cả hai đều được mô tả là phạm vi. Phạm vi bao gồmđộc quyền .
Craig Ringer
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.