ความแตกต่างระหว่าง '.. ' (double-dot) และ '…' (triple-dot) ในการสร้างช่วง?


111

ฉันเพิ่งเริ่มเรียนรู้ Ruby และ Ruby บน 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

เอกสารสำหรับช่วงบอกว่านี่:

ช่วงที่สร้างขึ้นโดยใช้การ..รันจากจุดเริ่มต้นไปยังจุดสิ้นสุดโดยรวม สิ่งที่สร้างขึ้นโดย...ไม่รวมค่าสิ้นสุด

ดังนั้นa..bเป็นเหมือนa <= x <= bในขณะที่เป็นเหมือนa...ba <= 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


เอกสารที่ใช้ไม่รวมสิ่งนี้ แต่ต้องอ่านส่วนของ Pickaxe ใน Rangesแทน ขอบคุณ @MarkAmery ( ดูด้านล่าง ) ที่แจ้งการอัปเดตนี้


11
ตัวอย่างที่ดีกว่า / สับสนน้อยกว่าด้านบน: (1..10).include? 10 #=> trueและ(1...10).include? 10 #=> false
timmcliu

@timmcliu แม้ว่าจะไม่เกี่ยวข้องกับการแสดงจุดที่ว่า(a..b) != (a...(b+1))แม้ว่าการแสดงอาร์เรย์ของพวกเขาจะเท่ากัน (เมื่อ a, b ∈ℤ) ฉันได้อัปเดตคำตอบของฉันเล็กน้อยเพื่อขยายความ
Andrew Marshall

ถ้า Range ไม่ใช่ชุดของค่าเหตุใดโค้ดส่วนนี้จึงถือว่า Range เป็นชุดของค่า: (1..5) .inject {| sum, n | sum + n}
VaVa

2
@ValentinVassilev Range ไม่ใช่ชุดของค่า แต่สามารถสร้างได้ injectมาจากEnumerableซึ่งRangeรวมถึง; Enumerableใช้#eachซึ่งการดำเนินการRange รายการที่สร้างขึ้นRange#eachจะไม่อยู่ภายในRangeออบเจ็กต์เอง
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
@ แอนดรูว์: ฉันก็คิดแบบนั้นเหมือนกัน แต่อาจจะลงไปที่ความหลากหลายสองจุดที่ต้องการมากกว่าและทำให้พิมพ์สั้นลง?
safetycopy

1
นอกจากนี้โปรดทราบว่า(a..b-1) != (a...b)แม้ว่าคำตอบนี้จะบอกเป็นนัยว่า
Andrew Marshall

1
(a..b-1) == (a ... b) เฉพาะในกรณีที่ a และ b เป็นจำนวนเต็มและคุณแจกแจงช่วงเป็นอาร์เรย์ พิจารณาช่วง (1.0 ... 3.5) - ก่อนหน้า 3.5 มีค่าเท่าใด ไม่ใช่ 2.5 อย่างแน่นอน!
Chris Heald

3

ขณะนี้เอกสาร API อธิบายพฤติกรรมนี้:

ช่วงที่สร้างขึ้นโดยใช้การ..รันจากจุดเริ่มต้นไปยังจุดสิ้นสุดโดยรวม สิ่งที่สร้างขึ้นโดย...ไม่รวมค่าสิ้นสุด

- 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...ba..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
ยังไม่ถูกต้องหลังจากแก้ไข แม้ว่าa& bจะเป็นจำนวนเต็ม แต่ช่วงจะต่างกัน ก็ต่อเมื่อแต่ละรายการถูกแปลงเป็นอาร์เรย์จะเหมือนกัน มีตัวอย่างการตอบโต้ที่เฉพาะเจาะจงอยู่ในคำตอบที่ยอมรับ
Andrew Marshall

2
@AndrewMarshall สิ่งที่ฉันตั้งใจจะพูดกับตัวอย่างนั้น (แต่เห็นได้ชัดว่าไม่ค่อยดีนัก) อยู่ในมาตราส่วนจำนวนเต็มมันทำงานในลักษณะนั้น นี่ไม่ใช่กรณีของมาตราส่วนเศษส่วนที่แม่นยำกว่าดังที่ระบุไว้ในคำตอบของคุณ ฉันคิดว่าช่วงมักจะใช้ในมาตราส่วนจำนวนเต็มซึ่งเป็นสาเหตุที่ฉันเชื่อว่าคำอธิบายดังกล่าวมีประโยชน์
Dennis

-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
ไม่ได้ตอบคำถามจริงๆ ทั้งสองถูกอธิบายว่าเป็นช่วง ช่วงรวมกับช่วงพิเศษ
Craig Ringer
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.