Unterschied zwischen '..' (Doppelpunkt) und '…' (Dreifachpunkt) bei der Bereichserzeugung?

110

Ich habe gerade angefangen, Ruby und Ruby on Rails zu lernen, und bin auf Validierungscode gestoßen, der Bereiche verwendet:

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

Zuerst dachte ich, der Unterschied liege in der Einbeziehung von Endpunkten, aber in den API-Dokumenten, die ich mir angesehen habe, schien es egal zu sein, ob es sich um Endpunkte handelte ..oder nicht ...: Es enthielt immer die Endpunkte.

Ich habe jedoch einige Tests in irb durchgeführt und es schien darauf hinzudeuten, dass ..beide Endpunkte enthalten sind, während ...nur die Untergrenze, nicht aber die Obergrenze enthalten ist. Ist das richtig?

juil
quelle

Antworten:

157

Die Dokumentation für Range lautet wie folgt:

Bereiche, die unter Verwendung von ..Lauf von Anfang bis Ende einschließlich konstruiert wurden . Diejenigen, die mit erstellt wurden, ...schließen den Endwert aus.

So a..bist wie a <= x <= b, während a...bist wie a <= x < b.


Beachten Sie, dass to_aein Bereich von Ganzzahlen zwar eine Sammlung von Ganzzahlen enthält, ein Bereich jedoch keine Wertemenge ist, sondern lediglich ein Paar von Start- / Endwerten:

(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


In den Dokumenten wurde dies früher nicht berücksichtigt. Stattdessen muss der Abschnitt über die Reichweite der Spitzhacke gelesen werden . Vielen Dank an @MarkAmery ( siehe unten ) für die Benachrichtigung über dieses Update.

Andrew Marshall
quelle
11
Besseres / weniger verwirrendes Beispiel als das obige: (1..10).include? 10 #=> trueund(1...10).include? 10 #=> false
timmcliu
@timmcliu Obwohl nicht relevant für die Veranschaulichung des Punktes, dass (a..b) != (a...(b+1))trotz ihrer Array-Darstellungen gleich (wenn a, b ∈ ∈). Ich habe meine Antwort ein wenig aktualisiert, um das zu erweitern.
Andrew Marshall
Wenn Range keine Menge von Werten ist, warum behandelt dieser Code Range dann als eine Menge von Werten: (1..5) .inject {| sum, n | sum + n}
VaVa
2
@ValentinVassilev Range ist kein Satz von Werten, kann diese jedoch generieren. injectkommt von Enumerabledenen Rangebeinhaltet; Enumerablenutzt #each, was Rangeimplementiert . Die von generierte Liste Range#eachist niemals im RangeObjekt selbst enthalten.
Andrew Marshall
6

Das ist richtig.

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]

Die Triple-Dot-Syntax ist weniger verbreitet, aber besser als (1..10-1).to_a

Chris Heald
quelle
12
Ich finde es wirklich bizarr, dass mehr Punkte bedeuten, dass der Bereich weniger Werte darstellt. Ich denke, es ist nur so, dass ..es häufiger vorkommt und daher weniger dafür bevorzugt wird.
Andrew Marshall
2
@ Andrew: Das habe ich auch gedacht, aber vielleicht liegt es daran, dass die Zweipunktsorte häufiger erwünscht und damit kürzer zu tippen ist?
Sicherheitskopie
1
Beachten Sie auch, dass (a..b-1) != (a...b)diese Antwort impliziert , dass dies der Fall ist.
Andrew Marshall
1
(a..b-1) == (a ... b) nur für den Fall, dass a und b ganze Zahlen sind und Sie die Bereiche in Arrays auflisten. Betrachten Sie den Bereich (1.0 ... 3.5) - was ist der Wert kurz vor 3.5? Mit Sicherheit nicht 2.5!
Chris Heald
3

Die API-Dokumente beschreiben nun dieses Verhalten:

Bereiche, die unter Verwendung von ..Lauf von Anfang bis Ende einschließlich konstruiert wurden . Diejenigen, die mit erstellt wurden, ...schließen den Endwert aus.

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

Mit anderen Worten:

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
quelle
1

a...b schließt den Endwert aus, während a..b enthält den Endwert.

Verhält sich beim Arbeiten mit ganzen Zahlen a...bwie folgt 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

Aber wirklich unterscheiden sich die Bereiche auf einer reellen Zahlenlinie .

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

Sie können dies sehen, wenn Sie in Bruchschritten inkrementieren.

>> (-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
quelle
1
Nach dem Bearbeiten immer noch falsch. Auch wenn a& bganze Zahlen sind, sind die Bereiche unterschiedlich. Nur wenn jedes in ein Array konvertiert wird, sind sie gleich. In der akzeptierten Antwort ist ein bestimmtes Gegenbeispiel vorhanden.
Andrew Marshall
2
@ AndrewMarshall Was ich mit diesem Beispiel sagen wollte (aber offensichtlich nicht sehr gut), ist auf einer ganzzahligen Skala, es verhält sich so. Dies ist auf einer genaueren Bruchskala nicht der Fall, wie in Ihrer Antwort ausgeführt. Ich gehe davon aus, dass Bereiche am häufigsten auf einer ganzzahligen Skala verwendet werden, weshalb ich eine solche Erklärung für hilfreich halte.
Dennis
-4

.. und ... bezeichnen einen Bereich.

Sieh es einfach in 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
quelle
2
Beantwortet die Frage jedoch nicht wirklich; beide werden als Bereiche beschrieben. Inklusive vs Exklusive Reichweite.
Craig Ringer