class Range
Ein Range-Objekt repräsentiert eine Sammlung von Werten, die zwischen gegebenen Anfangs- und Endwerten liegen.
Sie können ein Range-Objekt explizit mit
-
Einem Bereichs-Literal erstellen
# Ranges that use '..' to include the given end value. (1..4).to_a # => [1, 2, 3, 4] ('a'..'d').to_a # => ["a", "b", "c", "d"] # Ranges that use '...' to exclude the given end value. (1...4).to_a # => [1, 2, 3] ('a'...'d').to_a # => ["a", "b", "c"]
-
Methode
Range.new# Bereiche, die standardmäßig den gegebenen Endwert einschließen.
Range.new(1, 4).to_a # => [1, 2, 3, 4]Range.new(‘a’, ‘d’).to_a # => [“a”, “b”, “c”, “d”] # Bereiche, die das dritte Argumentexclude_endverwenden, um den gegebenen Endwert auszuschließen.Range.new(1, 4, true).to_a # => [1, 2, 3]Range.new(‘a’, ‘d’, true).to_a # => [“a”, “b”, “c”]
Beginnlose Bereiche
Ein *beginnloser* *Bereich* hat einen bestimmten Endwert, aber einen nil-Anfangswert. Ein solcher Bereich enthält alle Werte bis zum Endwert.
r = (..4) # => nil..4 r.begin # => nil r.include?(-50) # => true r.include?(4) # => true r = (...4) # => nil...4 r.include?(4) # => false Range.new(nil, 4) # => nil..4 Range.new(nil, 4, true) # => nil...4
Ein beginnloser Bereich kann zum Slicen eines Arrays verwendet werden
a = [1, 2, 3, 4] # Include the third array element in the slice r = (..2) # => nil..2 a[r] # => [1, 2, 3] # Exclude the third array element from the slice r = (...2) # => nil...2 a[r] # => [1, 2]
Die Methode each für einen beginnlosen Bereich löst eine Ausnahme aus.
Endlose Bereiche
Ein *endloser* *Bereich* hat einen bestimmten Anfangswert, aber einen nil-Endwert. Ein solcher Bereich enthält alle Werte ab dem Anfangswert.
r = (1..) # => 1.. r.end # => nil r.include?(50) # => true Range.new(1, nil) # => 1..
Das Literal für einen endlosen Bereich kann mit zwei oder drei Punkten geschrieben werden. Der Bereich hat in beiden Fällen die gleichen Elemente. Beachten Sie jedoch, dass die beiden nicht gleich sind
r0 = (1..) # => 1.. r1 = (1...) # => 1... r0.begin == r1.begin # => true r0.end == r1.end # => true r0 == r1 # => false
Ein endloser Bereich kann zum Slicen eines Arrays verwendet werden
a = [1, 2, 3, 4] r = (2..) # => 2.. a[r] # => [3, 4]
Die Methode each für einen endlosen Bereich ruft den gegebenen Block unendlich oft auf
a = [] r = (1..) r.each do |i| a.push(i) if i.even? break if i > 10 end a # => [2, 4, 6, 8, 10]
Ein Bereich kann sowohl beginnlos als auch endlos sein. Für literale beginnlose und endlose Bereiche muss mindestens der Anfang oder das Ende des Bereichs als expliziter nil-Wert angegeben werden. Es wird empfohlen, einen expliziten nil-Anfang und ein nil-Ende zu verwenden, da dies das ist, was Ruby für Range#inspect verwendet.
(nil..) # => (nil..nil) (..nil) # => (nil..nil) (nil..nil) # => (nil..nil)
Bereiche und andere Klassen
Ein Objekt kann in einen Bereich aufgenommen werden, wenn seine Klasse die Instanzmethode <=> implementiert. Zu den Ruby-Kernklassen, die dies tun, gehören Array, Complex, File::Stat, Float, Integer, Kernel, Module, Numeric, Rational, String, Symbol und Time.
Beispiel
t0 = Time.now # => 2021-09-19 09:22:48.4854986 -0500 t1 = Time.now # => 2021-09-19 09:22:56.0365079 -0500 t2 = Time.now # => 2021-09-19 09:23:08.5263283 -0500 (t0..t2).include?(t1) # => true (t0..t1).include?(t2) # => false
Ein Bereich kann nur iteriert werden, wenn seine Elemente die Instanzmethode succ implementieren. Zu den Ruby-Kernklassen, die dies tun, gehören Integer, String und Symbol (nicht aber die anderen oben genannten Klassen).
Iterator-Methoden umfassen
-
Aus Modul Enumerable:
each_entry,each_with_index,each_with_object,each_slice,each_consundreverse_each.
Beispiel
a = [] (1..4).each {|i| a.push(i) } a # => [1, 2, 3, 4]
Bereiche und benutzerdefinierte Klassen
Eine benutzerdefinierte Klasse, die in einem Bereich verwendet werden soll, muss die Instanzmethode <=> implementieren; siehe Integer#<=>. Um die Iteration zu ermöglichen, muss sie auch die Instanzmethode succ implementieren; siehe Integer#succ.
Die unten stehende Klasse implementiert sowohl <=> als auch succ und kann daher sowohl zur Konstruktion von Bereichen als auch zur Iteration über sie verwendet werden. Beachten Sie, dass das Modul Comparable enthalten ist, damit die Methode == auf Basis von <=> definiert wird.
# Represent a string of 'X' characters. class Xs include Comparable attr_accessor :length def initialize(n) @length = n end def succ Xs.new(@length + 1) end def <=>(other) @length <=> other.length end def to_s sprintf "%2d #{inspect}", @length end def inspect 'X' * @length end end r = Xs.new(3)..Xs.new(6) #=> XXX..XXXXXX r.to_a #=> [XXX, XXXX, XXXXX, XXXXXX] r.include?(Xs.new(5)) #=> true r.include?(Xs.new(7)) #=> false
Was gibt es hier
Zunächst, was anderswo steht. Klasse Range
-
Erbt von Klasse Object.
-
Beinhaltet das Modul Enumerable, das Dutzende zusätzlicher Methoden bereitstellt.
Hier bietet die Klasse Range Methoden, die nützlich sind für
Methoden zum Erstellen eines Bereichs
-
::new: Gibt einen neuen Bereich zurück.
Methoden zum Abfragen
-
begin: Gibt den fürselfangegebenen Anfangswert zurück. -
bsearch: Gibt ein Element ausselfzurück, das durch binäre Suche ausgewählt wurde. -
count: Gibt eine Zählung der Elemente inselfzurück. -
end: Gibt den fürselfangegebenen Endwert zurück. -
exclude_end?: Gibt zurück, ob das Endobjekt ausgeschlossen ist. -
first: Gibt die ersten Elemente vonselfzurück. -
hash: Gibt den ganzzahligen Hash-Code zurück. -
last: Gibt die letzten Elemente vonselfzurück. -
max: Gibt die maximalen Werte inselfzurück. -
min: Gibt die minimalen Werte inselfzurück. -
minmax: Gibt die minimalen und maximalen Werte inselfzurück. -
size: Gibt die Anzahl der Elemente inselfzurück.
Methoden zum Vergleichen
-
==: Gibt zurück, ob ein gegebenes Objekt gleichselfist (verwendet==). -
===: Gibt zurück, ob das gegebene Objekt zwischen dem Anfangs- und Endwert liegt. -
cover?: Gibt zurück, ob ein gegebenes Objekt innerhalb vonselfliegt. -
eql?: Gibt zurück, ob ein gegebenes Objekt gleichselfist (verwendeteql?). -
include?(alias alsmember?): Gibt zurück, ob ein gegebenes Objekt ein Element vonselfist.
Methoden zur Iteration
-
%: Erfordert das Argumentn; ruft den Block mit jedemn-ten Element vonselfauf. -
each: Ruft den Block mit jedem Element vonselfauf. -
step: Nimmt ein optionales Argumentn(standardmäßig 1); ruft den Block mit jedemn-ten Element vonselfauf.
Methoden zur Konvertierung
-
inspect: Gibt eine Zeichenfolgendarstellung vonselfzurück (verwendetinspect). -
to_a(alias alsentries): Gibt die Elemente vonselfin einem Array zurück. -
to_s: Gibt eine Zeichenfolgendarstellung vonselfzurück (verwendetto_s).
Methoden für die Arbeit mit JSON
-
::json_create: Gibt ein neues Range-Objekt zurück, das aus dem gegebenen Objekt konstruiert wurde. -
as_json: Gibt einen 2-Element-Hash zurück, derselfrepräsentiert. -
to_json: Gibt eine JSON-Zeichenfolge zurück, dieselfrepräsentiert.
Um diese Methoden verfügbar zu machen
require 'json/add/range'
Öffentliche Klassenmethoden
Source
# File ext/json/lib/json/add/range.rb, line 9 def self.json_create(object) new(*object['a']) end
Siehe as_json.
Source
static VALUE
range_initialize(int argc, VALUE *argv, VALUE range)
{
VALUE beg, end, flags;
rb_scan_args(argc, argv, "21", &beg, &end, &flags);
range_modify(range);
range_init(range, beg, end, RBOOL(RTEST(flags)));
return Qnil;
}
Gibt einen neuen Bereich basierend auf den gegebenen Objekten begin und end zurück. Das optionale Argument exclude_end bestimmt, ob das Objekt end als letztes Objekt im Bereich enthalten ist.
Range.new(2, 5).to_a # => [2, 3, 4, 5] Range.new(2, 5, true).to_a # => [2, 3, 4] Range.new('a', 'd').to_a # => ["a", "b", "c", "d"] Range.new('a', 'd', true).to_a # => ["a", "b", "c"]
Öffentliche Instanzmethoden
Source
static VALUE
range_percent_step(VALUE range, VALUE step)
{
return range_step(1, &step, range);
}
Gleich wie step (liefert aber keinen Standardwert für n). Die Methode ist praktisch für die ausdrucksstarke Erzeugung von Enumerator::ArithmeticSequence.
array = [0, 1, 2, 3, 4, 5, 6] # slice each second element: seq = (0..) % 2 #=> ((0..).%(2)) array[seq] #=> [0, 2, 4, 6] # or just array[(0..) % 2] #=> [0, 2, 4, 6]
Beachten Sie, dass aufgrund der Operatorrangfolge in Ruby Klammern um den Bereich in diesem Fall zwingend erforderlich sind
(0..7) % 2 #=> ((0..7).%(2)) -- as expected 0..7 % 2 #=> 0..1 -- parsed as 0..(7 % 2)
Source
static VALUE
range_eq(VALUE range, VALUE obj)
{
if (range == obj)
return Qtrue;
if (!rb_obj_is_kind_of(obj, rb_cRange))
return Qfalse;
return rb_exec_recursive_paired(recursive_equal, range, obj, obj);
}
Gibt true zurück, wenn und nur wenn
-
otherein Bereich ist. -
other.begin == self.begin. -
other.end == self.end. -
other.exclude_end? == self.exclude_end?.
Andernfalls wird false zurückgegeben.
r = (1..5) r == (1..5) # => true r = Range.new(1, 5) r == 'foo' # => false r == (2..5) # => false r == (1..4) # => false r == (1...5) # => false r == Range.new(1, 5, true) # => false
Beachten Sie, dass selbst bei gleichem Argument die Rückgabewerte von == und eql? unterschiedlich sein können
(1..2) == (1..2.0) # => true (1..2).eql? (1..2.0) # => false
Verwandt: Range#eql?.
Source
static VALUE
range_eqq(VALUE range, VALUE val)
{
return r_cover_p(range, RANGE_BEG(range), RANGE_END(range), val);
}
Gibt true zurück, wenn object zwischen self.begin und self.end liegt. Andernfalls false
(1..4) === 2 # => true (1..4) === 5 # => false (1..4) === 'a' # => false (1..4) === 4 # => true (1...4) === 4 # => false ('a'..'d') === 'c' # => true ('a'..'d') === 'e' # => false
Eine Fallunterscheidung verwendet die Methode ===, und so
case 79 when (1..50) "low" when (51..75) "medium" when (76..100) "high" end # => "high" case "2.6.5" when ..."2.4" "EOL" when "2.4"..."2.5" "maintenance" when "2.5"..."3.0" "stable" when "3.1".. "upcoming" end # => "stable"
Source
# File ext/json/lib/json/add/range.rb, line 31 def as_json(*) { JSON.create_id => self.class.name, 'a' => [ first, last, exclude_end? ] } end
Die Methoden Range#as_json und Range.json_create können verwendet werden, um ein Range-Objekt zu serialisieren und zu deserialisieren; siehe Marshal.
Die Methode Range#as_json serialisiert self und gibt einen 2-Element-Hash zurück, der self repräsentiert.
require 'json/add/range' x = (1..4).as_json # => {"json_class"=>"Range", "a"=>[1, 4, false]} y = (1...4).as_json # => {"json_class"=>"Range", "a"=>[1, 4, true]} z = ('a'..'d').as_json # => {"json_class"=>"Range", "a"=>["a", "d", false]}
Die Methode JSON.create deserialisiert einen solchen Hash und gibt ein Range-Objekt zurück.
Range.json_create(x) # => 1..4 Range.json_create(y) # => 1...4 Range.json_create(z) # => "a".."d"
Source
static VALUE
range_begin(VALUE range)
{
return RANGE_BEG(range);
}
Gibt das Objekt zurück, das den Anfang von self definiert.
(1..4).begin # => 1 (..2).begin # => nil
Verwandt: Range#first, Range#end.
Source
static VALUE
range_bsearch(VALUE range)
{
VALUE beg, end, satisfied = Qnil;
int smaller;
/* Implementation notes:
* Floats are handled by mapping them to 64 bits integers.
* Apart from sign issues, floats and their 64 bits integer have the
* same order, assuming they are represented as exponent followed
* by the mantissa. This is true with or without implicit bit.
*
* Finding the average of two ints needs to be careful about
* potential overflow (since float to long can use 64 bits).
*
* The half-open interval (low, high] indicates where the target is located.
* The loop continues until low and high are adjacent.
*
* -1/2 can be either 0 or -1 in C89. However, when low and high are not adjacent,
* the rounding direction of mid = (low + high) / 2 does not affect the result of
* the binary search.
*
* Note that -0.0 is mapped to the same int as 0.0 as we don't want
* (-1...0.0).bsearch to yield -0.0.
*/
#define BSEARCH(conv, excl) \
do { \
RETURN_ENUMERATOR(range, 0, 0); \
if (!(excl)) high++; \
low--; \
while (low + 1 < high) { \
mid = ((high < 0) == (low < 0)) ? low + ((high - low) / 2) \
: (low + high) / 2; \
BSEARCH_CHECK(conv(mid)); \
if (smaller) { \
high = mid; \
} \
else { \
low = mid; \
} \
} \
return satisfied; \
} while (0)
#define BSEARCH_FIXNUM(beg, end, excl) \
do { \
long low = FIX2LONG(beg); \
long high = FIX2LONG(end); \
long mid; \
BSEARCH(INT2FIX, (excl)); \
} while (0)
beg = RANGE_BEG(range);
end = RANGE_END(range);
if (FIXNUM_P(beg) && FIXNUM_P(end)) {
BSEARCH_FIXNUM(beg, end, EXCL(range));
}
#if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T)
else if (RB_FLOAT_TYPE_P(beg) || RB_FLOAT_TYPE_P(end)) {
int64_t low = double_as_int64(NIL_P(beg) ? -HUGE_VAL : RFLOAT_VALUE(rb_Float(beg)));
int64_t high = double_as_int64(NIL_P(end) ? HUGE_VAL : RFLOAT_VALUE(rb_Float(end)));
int64_t mid;
BSEARCH(int64_as_double_to_num, EXCL(range));
}
#endif
else if (is_integer_p(beg) && is_integer_p(end)) {
RETURN_ENUMERATOR(range, 0, 0);
return bsearch_integer_range(beg, end, EXCL(range));
}
else if (is_integer_p(beg) && NIL_P(end)) {
VALUE diff = LONG2FIX(1);
RETURN_ENUMERATOR(range, 0, 0);
while (1) {
VALUE mid = rb_funcall(beg, '+', 1, diff);
BSEARCH_CHECK(mid);
if (smaller) {
if (FIXNUM_P(beg) && FIXNUM_P(mid)) {
BSEARCH_FIXNUM(beg, mid, false);
}
else {
return bsearch_integer_range(beg, mid, false);
}
}
diff = rb_funcall(diff, '*', 1, LONG2FIX(2));
beg = mid;
}
}
else if (NIL_P(beg) && is_integer_p(end)) {
VALUE diff = LONG2FIX(-1);
RETURN_ENUMERATOR(range, 0, 0);
while (1) {
VALUE mid = rb_funcall(end, '+', 1, diff);
BSEARCH_CHECK(mid);
if (!smaller) {
if (FIXNUM_P(mid) && FIXNUM_P(end)) {
BSEARCH_FIXNUM(mid, end, false);
}
else {
return bsearch_integer_range(mid, end, false);
}
}
diff = rb_funcall(diff, '*', 1, LONG2FIX(2));
end = mid;
}
}
else {
rb_raise(rb_eTypeError, "can't do binary search for %s", rb_obj_classname(beg));
}
return range;
}
Gibt ein Element aus self zurück, das durch binäre Suche ausgewählt wurde.
Siehe Binäre Suche.
Source
static VALUE
range_count(int argc, VALUE *argv, VALUE range)
{
if (argc != 0) {
/* It is odd for instance (1...).count(0) to return Infinity. Just let
* it loop. */
return rb_call_super(argc, argv);
}
else if (rb_block_given_p()) {
/* Likewise it is odd for instance (1...).count {|x| x == 0 } to return
* Infinity. Just let it loop. */
return rb_call_super(argc, argv);
}
VALUE beg = RANGE_BEG(range), end = RANGE_END(range);
if (NIL_P(beg) || NIL_P(end)) {
/* We are confident that the answer is Infinity. */
return DBL2NUM(HUGE_VAL);
}
if (is_integer_p(beg)) {
VALUE size = range_size(range);
if (!NIL_P(size)) {
return size;
}
}
return rb_call_super(argc, argv);
}
Gibt die Anzahl der Elemente zurück, basierend auf einem Argument- oder Blockkriterium, falls angegeben.
Ohne Argument und ohne Block gibt es die Anzahl der Elemente zurück
(1..4).count # => 4 (1...4).count # => 3 ('a'..'d').count # => 4 ('a'...'d').count # => 3 (1..).count # => Infinity (..4).count # => Infinity
Mit dem Argument object gibt es die Anzahl der in self gefundenen object zurück, die normalerweise null oder eins beträgt
(1..4).count(2) # => 1 (1..4).count(5) # => 0 (1..4).count('a') # => 0
Mit einem gegebenen Block wird der Block mit jedem Element aufgerufen; gibt die Anzahl der Elemente zurück, für die der Block einen wahrheitsgemäßen Wert zurückgibt
(1..4).count {|element| element < 3 } # => 2
Verwandt: Range#size.
Source
static VALUE
range_cover(VALUE range, VALUE val)
{
VALUE beg, end;
beg = RANGE_BEG(range);
end = RANGE_END(range);
if (rb_obj_is_kind_of(val, rb_cRange)) {
return RBOOL(r_cover_range_p(range, beg, end, val));
}
return r_cover_p(range, beg, end, val);
}
Gibt true zurück, wenn das gegebene Argument innerhalb von self liegt, andernfalls false.
Mit einem Nicht-Bereichs-Argument object wird mit <= und < evaluiert.
Für einen Bereich self mit eingeschlossenem Endwert (#exclude_end? == false) wird wie folgt evaluiert
self.begin <= object <= self.end
Beispiele
r = (1..4) r.cover?(1) # => true r.cover?(4) # => true r.cover?(0) # => false r.cover?(5) # => false r.cover?('foo') # => false r = ('a'..'d') r.cover?('a') # => true r.cover?('d') # => true r.cover?(' ') # => false r.cover?('e') # => false r.cover?(0) # => false
Für einen Bereich r mit ausgeschlossenem Endwert (#exclude_end? == true) wird wie folgt evaluiert
r.begin <= object < r.end
Beispiele
r = (1...4) r.cover?(1) # => true r.cover?(3) # => true r.cover?(0) # => false r.cover?(4) # => false r.cover?('foo') # => false r = ('a'...'d') r.cover?('a') # => true r.cover?('c') # => true r.cover?(' ') # => false r.cover?('d') # => false r.cover?(0) # => false
Mit einem Bereichsargument range werden das erste und das letzte Element von self und range verglichen.
r = (1..4) r.cover?(1..4) # => true r.cover?(0..4) # => false r.cover?(1..5) # => false r.cover?('a'..'d') # => false r = (1...4) r.cover?(1..3) # => true r.cover?(1..4) # => false
Wenn Anfang und Ende numerisch sind, verhält sich cover? wie include?.
(1..3).cover?(1.5) # => true (1..3).include?(1.5) # => true
Wenn sie nicht numerisch sind, können sich die beiden Methoden unterscheiden.
('a'..'d').cover?('cc') # => true ('a'..'d').include?('cc') # => false
Gibt false zurück, wenn entweder
-
Der Anfangswert von
selfgrößer ist als sein Endwert. -
Ein interner Aufruf von
<=>gibtnilzurück; das heißt, die Operanden sind nicht vergleichbar.
Beginnlose Bereiche umfassen alle Werte desselben Typs vor dem Ende, wobei das Ende bei exklusiven Bereichen ausgeschlossen ist. Beginnlose Bereiche umfassen Bereiche, die vor dem Ende des beginnlosen Bereichs enden, oder am Ende des beginnlosen Bereichs für inklusive Bereiche.
(..2).cover?(1) # => true (..2).cover?(2) # => true (..2).cover?(3) # => false (...2).cover?(2) # => false (..2).cover?("2") # => false (..2).cover?(..2) # => true (..2).cover?(...2) # => true (..2).cover?(.."2") # => false (...2).cover?(..2) # => false
Endlose Bereiche umfassen alle Werte desselben Typs nach dem Anfang. Endlose exklusive Bereiche umfassen keine endlosen inklusiven Bereiche.
(2..).cover?(1) # => false (2..).cover?(3) # => true (2...).cover?(3) # => true (2..).cover?(2) # => true (2..).cover?("2") # => false (2..).cover?(2..) # => true (2..).cover?(2...) # => true (2..).cover?("2"..) # => false (2...).cover?(2..) # => false (2...).cover?(3...) # => true (2...).cover?(3..) # => false (3..).cover?(2..) # => false
Bereiche, die sowohl beginnlos als auch endlos sind, umfassen alle Werte und Bereiche und geben für alle Argumente true zurück, mit der Ausnahme, dass beginnlose und endlose exklusive Bereiche keine endlosen inklusiven Bereiche umfassen.
(nil...).cover?(Object.new) # => true (nil...).cover?(nil...) # => true (nil..).cover?(nil...) # => true (nil...).cover?(nil..) # => false (nil...).cover?(1..) # => false
Verwandt: Range#include?.
Source
static VALUE
range_each(VALUE range)
{
VALUE beg, end;
long i;
RETURN_SIZED_ENUMERATOR(range, 0, 0, range_enum_size);
beg = RANGE_BEG(range);
end = RANGE_END(range);
if (FIXNUM_P(beg) && NIL_P(end)) {
range_each_fixnum_endless(beg);
}
else if (FIXNUM_P(beg) && FIXNUM_P(end)) { /* fixnums are special */
return range_each_fixnum_loop(beg, end, range);
}
else if (RB_INTEGER_TYPE_P(beg) && (NIL_P(end) || RB_INTEGER_TYPE_P(end))) {
if (SPECIAL_CONST_P(end) || RBIGNUM_POSITIVE_P(end)) { /* end >= FIXNUM_MIN */
if (!FIXNUM_P(beg)) {
if (RBIGNUM_NEGATIVE_P(beg)) {
do {
rb_yield(beg);
} while (!FIXNUM_P(beg = rb_big_plus(beg, INT2FIX(1))));
if (NIL_P(end)) range_each_fixnum_endless(beg);
if (FIXNUM_P(end)) return range_each_fixnum_loop(beg, end, range);
}
else {
if (NIL_P(end)) range_each_bignum_endless(beg);
if (FIXNUM_P(end)) return range;
}
}
if (FIXNUM_P(beg)) {
i = FIX2LONG(beg);
do {
rb_yield(LONG2FIX(i));
} while (POSFIXABLE(++i));
beg = LONG2NUM(i);
}
ASSUME(!FIXNUM_P(beg));
ASSUME(!SPECIAL_CONST_P(end));
}
if (!FIXNUM_P(beg) && RBIGNUM_SIGN(beg) == RBIGNUM_SIGN(end)) {
if (EXCL(range)) {
while (rb_big_cmp(beg, end) == INT2FIX(-1)) {
rb_yield(beg);
beg = rb_big_plus(beg, INT2FIX(1));
}
}
else {
VALUE c;
while ((c = rb_big_cmp(beg, end)) != INT2FIX(1)) {
rb_yield(beg);
if (c == INT2FIX(0)) break;
beg = rb_big_plus(beg, INT2FIX(1));
}
}
}
}
else if (SYMBOL_P(beg) && (NIL_P(end) || SYMBOL_P(end))) { /* symbols are special */
beg = rb_sym2str(beg);
if (NIL_P(end)) {
rb_str_upto_endless_each(beg, sym_each_i, 0);
}
else {
rb_str_upto_each(beg, rb_sym2str(end), EXCL(range), sym_each_i, 0);
}
}
else {
VALUE tmp = rb_check_string_type(beg);
if (!NIL_P(tmp)) {
if (!NIL_P(end)) {
rb_str_upto_each(tmp, end, EXCL(range), each_i, 0);
}
else {
rb_str_upto_endless_each(tmp, each_i, 0);
}
}
else {
if (!discrete_object_p(beg)) {
rb_raise(rb_eTypeError, "can't iterate from %s",
rb_obj_classname(beg));
}
if (!NIL_P(end))
range_each_func(range, each_i, 0);
else
for (;; beg = rb_funcallv(beg, id_succ, 0, 0))
rb_yield(beg);
}
}
return range;
}
Mit einem gegebenen Block wird jedes Element von self an den Block übergeben.
a = [] (1..4).each {|element| a.push(element) } # => 1..4 a # => [1, 2, 3, 4]
Löst eine Ausnahme aus, es sei denn, self.first.respond_to?(:succ).
Ohne einen gegebenen Block wird ein Enumerator zurückgegeben.
Source
static VALUE
range_end(VALUE range)
{
return RANGE_END(range);
}
Gibt das Objekt zurück, das das Ende von self definiert.
(1..4).end # => 4 (1...4).end # => 4 (1..).end # => nil
Verwandt: Range#begin, Range#last.
Source
static VALUE
range_eql(VALUE range, VALUE obj)
{
if (range == obj)
return Qtrue;
if (!rb_obj_is_kind_of(obj, rb_cRange))
return Qfalse;
return rb_exec_recursive_paired(recursive_eql, range, obj, obj);
}
Gibt true zurück, wenn und nur wenn
-
otherein Bereich ist. -
other.begin.eql?(self.begin). -
other.end.eql?(self.end). -
other.exclude_end? == self.exclude_end?.
Andernfalls wird false zurückgegeben.
r = (1..5) r.eql?(1..5) # => true r = Range.new(1, 5) r.eql?('foo') # => false r.eql?(2..5) # => false r.eql?(1..4) # => false r.eql?(1...5) # => false r.eql?(Range.new(1, 5, true)) # => false
Beachten Sie, dass selbst bei gleichem Argument die Rückgabewerte von == und eql? unterschiedlich sein können
(1..2) == (1..2.0) # => true (1..2).eql? (1..2.0) # => false
Verwandt: Range#==.
Source
static VALUE
range_exclude_end_p(VALUE range)
{
return RBOOL(EXCL(range));
}
Gibt true zurück, wenn self seinen Endwert ausschließt; andernfalls false.
Range.new(2, 5).exclude_end? # => false Range.new(2, 5, true).exclude_end? # => true (2..5).exclude_end? # => false (2...5).exclude_end? # => true
Source
static VALUE
range_first(int argc, VALUE *argv, VALUE range)
{
VALUE n, ary[2];
if (NIL_P(RANGE_BEG(range))) {
rb_raise(rb_eRangeError, "cannot get the first element of beginless range");
}
if (argc == 0) return RANGE_BEG(range);
rb_scan_args(argc, argv, "1", &n);
ary[0] = n;
ary[1] = rb_ary_new2(NUM2LONG(n));
rb_block_call(range, idEach, 0, 0, first_i, (VALUE)ary);
return ary[1];
}
Ohne Argument gibt es das erste Element von self zurück, falls es existiert.
(1..4).first # => 1 ('a'..'d').first # => "a"
Mit einem gegebenen nicht-negativen ganzzahligen Argument n werden die ersten n Elemente in einem Array zurückgegeben.
(1..10).first(3) # => [1, 2, 3] (1..10).first(0) # => [] (1..4).first(50) # => [1, 2, 3, 4]
Löst eine Ausnahme aus, wenn kein erstes Element vorhanden ist.
(..4).first # Raises RangeError
Source
static VALUE
range_hash(VALUE range)
{
st_index_t hash = EXCL(range);
VALUE v;
hash = rb_hash_start(hash);
v = rb_hash(RANGE_BEG(range));
hash = rb_hash_uint(hash, NUM2LONG(v));
v = rb_hash(RANGE_END(range));
hash = rb_hash_uint(hash, NUM2LONG(v));
hash = rb_hash_uint(hash, EXCL(range) << 24);
hash = rb_hash_end(hash);
return ST2FIX(hash);
}
Gibt den ganzzahligen Hash-Wert für self zurück. Zwei Bereichsobjekte r0 und r1 haben den gleichen Hash-Wert, wenn und nur wenn r0.eql?(r1).
Verwandt: Range#eql?, Object#hash.
Gibt true zurück, wenn object ein Element von self ist, andernfalls false.
(1..4).include?(2) # => true (1..4).include?(5) # => false (1..4).include?(4) # => true (1...4).include?(4) # => false ('a'..'d').include?('b') # => true ('a'..'d').include?('e') # => false ('a'..'d').include?('B') # => false ('a'..'d').include?('d') # => true ('a'...'d').include?('d') # => false
Wenn Anfang und Ende numerisch sind, verhält sich include? wie cover?.
(1..3).include?(1.5) # => true (1..3).cover?(1.5) # => true
Wenn sie nicht numerisch sind, können sich die beiden Methoden unterscheiden.
('a'..'d').include?('cc') # => false ('a'..'d').cover?('cc') # => true
Verwandt: Range#cover?.
Source
static VALUE
range_inspect(VALUE range)
{
return rb_exec_recursive(inspect_range, range, 0);
}
Gibt eine Zeichenfolgendarstellung von self zurück, einschließlich begin.inspect und end.inspect.
(1..4).inspect # => "1..4" (1...4).inspect # => "1...4" (1..).inspect # => "1.." (..4).inspect # => "..4"
Beachten Sie, dass die Rückgaben von to_s und inspect unterschiedlich sein können.
('a'..'d').to_s # => "a..d" ('a'..'d').inspect # => "\"a\"..\"d\""
Verwandt: Range#to_s.
Source
static VALUE
range_last(int argc, VALUE *argv, VALUE range)
{
if (NIL_P(RANGE_END(range))) {
rb_raise(rb_eRangeError, "cannot get the last element of endless range");
}
if (argc == 0) return RANGE_END(range);
if (integer_end_optimizable(range)) {
return rb_int_range_last(argc, argv, range);
}
return rb_ary_last(argc, argv, rb_Array(range));
}
Ohne Argument gibt es das letzte Element von self zurück, falls es existiert.
(1..4).last # => 4 ('a'..'d').last # => "d"
Beachten Sie, dass last ohne Argument das Endelement von self zurückgibt, auch wenn exclude_end? true ist.
(1...4).last # => 4 ('a'...'d').last # => "d"
Mit einem gegebenen nicht-negativen ganzzahligen Argument n werden die letzten n Elemente in einem Array zurückgegeben.
(1..10).last(3) # => [8, 9, 10] (1..10).last(0) # => [] (1..4).last(50) # => [1, 2, 3, 4]
Beachten Sie, dass last mit einem Argument nicht das Endelement von self zurückgibt, wenn exclude_end? true ist.
(1...4).last(3) # => [1, 2, 3] ('a'...'d').last(3) # => ["a", "b", "c"]
Löst eine Ausnahme aus, wenn kein letztes Element vorhanden ist.
(1..).last # Raises RangeError
Source
static VALUE
range_max(int argc, VALUE *argv, VALUE range)
{
VALUE e = RANGE_END(range);
int nm = FIXNUM_P(e) || rb_obj_is_kind_of(e, rb_cNumeric);
if (NIL_P(RANGE_END(range))) {
rb_raise(rb_eRangeError, "cannot get the maximum of endless range");
}
VALUE b = RANGE_BEG(range);
if (rb_block_given_p() || (EXCL(range) && !nm)) {
if (NIL_P(b)) {
rb_raise(rb_eRangeError, "cannot get the maximum of beginless range with custom comparison method");
}
return rb_call_super(argc, argv);
}
else if (argc) {
VALUE ary[2];
ID reverse_each;
CONST_ID(reverse_each, "reverse_each");
rb_scan_args(argc, argv, "1", &ary[0]);
ary[1] = rb_ary_new2(NUM2LONG(ary[0]));
rb_block_call(range, reverse_each, 0, 0, first_i, (VALUE)ary);
return ary[1];
#if 0
if (integer_end_optimizable(range)) {
return rb_int_range_last(argc, argv, range, true);
}
return rb_ary_reverse(rb_ary_last(argc, argv, rb_Array(range)));
#endif
}
else {
int c = NIL_P(b) ? -1 : OPTIMIZED_CMP(b, e);
if (c > 0)
return Qnil;
if (EXCL(range)) {
if (!RB_INTEGER_TYPE_P(e)) {
rb_raise(rb_eTypeError, "cannot exclude non Integer end value");
}
if (c == 0) return Qnil;
if (!NIL_P(b) && !RB_INTEGER_TYPE_P(b)) {
rb_raise(rb_eTypeError, "cannot exclude end value with non Integer begin value");
}
if (FIXNUM_P(e)) {
return LONG2NUM(FIX2LONG(e) - 1);
}
return rb_int_minus(e,INT2FIX(1));
}
return e;
}
}
Gibt den Maximalwert in self zurück, unter Verwendung der Methode <=> oder eines gegebenen Blocks für den Vergleich.
Ohne Argument und ohne Block gegeben, gibt es das Element mit dem höchsten Wert in self zurück.
(1..4).max # => 4 ('a'..'d').max # => "d" (-4..-1).max # => -1
Mit einem gegebenen nicht-negativen ganzzahligen Argument n und ohne Block gegeben, gibt es die n Elemente mit dem höchsten Wert in self in einem Array zurück.
(1..4).max(2) # => [4, 3] ('a'..'d').max(2) # => ["d", "c"] (-4..-1).max(2) # => [-1, -2] (1..4).max(50) # => [4, 3, 2, 1]
Wenn ein Block gegeben ist, wird er aufgerufen
-
Zuerst mit den ersten beiden Elementen von
self. -
Dann sequenziell mit dem bisherigen Maximum und dem nächsten Element von
self.
Zur Veranschaulichung
(1..4).max {|a, b| p [a, b]; a <=> b } # => 4
Ausgabe
[2, 1] [3, 2] [4, 3]
Ohne Argument und mit gegebenem Block, gibt es den Rückgabewert des letzten Aufrufs des Blocks zurück.
(1..4).max {|a, b| -(a <=> b) } # => 1
Mit einem gegebenen nicht-negativen ganzzahligen Argument n und einem gegebenen Block, gibt es die Rückgabewerte der letzten n Aufrufe des Blocks in einem Array zurück.
(1..4).max(2) {|a, b| -(a <=> b) } # => [1, 2] (1..4).max(50) {|a, b| -(a <=> b) } # => [1, 2, 3, 4]
Gibt ein leeres Array zurück, wenn n null ist.
(1..4).max(0) # => [] (1..4).max(0) {|a, b| -(a <=> b) } # => []
Gibt nil oder ein leeres Array zurück, wenn
-
Der Anfangswert des Bereichs ist größer als sein Endwert.
(4..1).max # => nil (4..1).max(2) # => [] (4..1).max {|a, b| -(a <=> b) } # => nil (4..1).max(2) {|a, b| -(a <=> b) } # => []
-
Der Anfangswert eines exklusiven Bereichs ist gleich dem Endwert.
(1...1).max # => nil (1...1).max(2) # => [] (1...1).max {|a, b| -(a <=> b) } # => nil (1...1).max(2) {|a, b| -(a <=> b) } # => []
Löst eine Ausnahme aus, wenn entweder
-
selfein endloser Bereich ist:(1..). -
Ein Block gegeben ist und
selfein beginnloser Bereich ist.
Verwandt: Range#min, Range#minmax.
Source
static VALUE
range_include(VALUE range, VALUE val)
{
VALUE ret = range_include_internal(range, val);
if (!UNDEF_P(ret)) return ret;
return rb_call_super(1, &val);
}
Source
static VALUE
range_min(int argc, VALUE *argv, VALUE range)
{
if (NIL_P(RANGE_BEG(range))) {
rb_raise(rb_eRangeError, "cannot get the minimum of beginless range");
}
if (rb_block_given_p()) {
if (NIL_P(RANGE_END(range))) {
rb_raise(rb_eRangeError, "cannot get the minimum of endless range with custom comparison method");
}
return rb_call_super(argc, argv);
}
else if (argc != 0) {
return range_first(argc, argv, range);
}
else {
VALUE b = RANGE_BEG(range);
VALUE e = RANGE_END(range);
int c = NIL_P(e) ? -1 : OPTIMIZED_CMP(b, e);
if (c > 0 || (c == 0 && EXCL(range)))
return Qnil;
return b;
}
}
Gibt den Minimalwert in self zurück, unter Verwendung der Methode <=> oder eines gegebenen Blocks für den Vergleich.
Ohne Argument und ohne Block gegeben, gibt es das Element mit dem niedrigsten Wert in self zurück.
(1..4).min # => 1 ('a'..'d').min # => "a" (-4..-1).min # => -4
Mit einem gegebenen nicht-negativen ganzzahligen Argument n und ohne Block gegeben, gibt es die n Elemente mit dem niedrigsten Wert in self in einem Array zurück.
(1..4).min(2) # => [1, 2] ('a'..'d').min(2) # => ["a", "b"] (-4..-1).min(2) # => [-4, -3] (1..4).min(50) # => [1, 2, 3, 4]
Wenn ein Block gegeben ist, wird er aufgerufen
-
Zuerst mit den ersten beiden Elementen von
self. -
Dann sequenziell mit dem bisherigen Minimum und dem nächsten Element von
self.
Zur Veranschaulichung
(1..4).min {|a, b| p [a, b]; a <=> b } # => 1
Ausgabe
[2, 1] [3, 1] [4, 1]
Ohne Argument und mit gegebenem Block, gibt es den Rückgabewert des letzten Aufrufs des Blocks zurück.
(1..4).min {|a, b| -(a <=> b) } # => 4
Mit einem gegebenen nicht-negativen ganzzahligen Argument n und einem gegebenen Block, gibt es die Rückgabewerte der letzten n Aufrufe des Blocks in einem Array zurück.
(1..4).min(2) {|a, b| -(a <=> b) } # => [4, 3] (1..4).min(50) {|a, b| -(a <=> b) } # => [4, 3, 2, 1]
Gibt ein leeres Array zurück, wenn n null ist.
(1..4).min(0) # => [] (1..4).min(0) {|a, b| -(a <=> b) } # => []
Gibt nil oder ein leeres Array zurück, wenn
-
Der Anfangswert des Bereichs ist größer als sein Endwert.
(4..1).min # => nil (4..1).min(2) # => [] (4..1).min {|a, b| -(a <=> b) } # => nil (4..1).min(2) {|a, b| -(a <=> b) } # => []
-
Der Anfangswert eines exklusiven Bereichs ist gleich dem Endwert.
(1...1).min # => nil (1...1).min(2) # => [] (1...1).min {|a, b| -(a <=> b) } # => nil (1...1).min(2) {|a, b| -(a <=> b) } # => []
Löst eine Ausnahme aus, wenn entweder
-
selfist ein beginnloser Bereich:(..4). -
Ein Block ist gegeben und
selfist ein endloser Bereich.
Verwandt: Range#max, Range#minmax.
Source
static VALUE
range_minmax(VALUE range)
{
if (rb_block_given_p()) {
return rb_call_super(0, NULL);
}
return rb_assoc_new(
rb_funcall(range, id_min, 0),
rb_funcall(range, id_max, 0)
);
}
Gibt ein 2-Element-Array zurück, das den minimalen und maximalen Wert in self enthält, entweder gemäß der Vergleichsmethode <=> oder einem gegebenen Block.
Ohne Block gegeben, gibt es das Minimum und Maximum zurück, unter Verwendung von <=> für den Vergleich.
(1..4).minmax # => [1, 4] (1...4).minmax # => [1, 3] ('a'..'d').minmax # => ["a", "d"] (-4..-1).minmax # => [-4, -1]
Mit einem gegebenen Block muss der Block eine Ganzzahl zurückgeben.
-
Negativ, wenn
akleiner alsbist. -
Null, wenn
aundbgleich sind. -
Positiv, wenn
agrößer alsbist.
Der Block wird self.size Mal aufgerufen, um Elemente zu vergleichen; gibt ein 2-Element- mit dem Minimum und Maximum aus Arrayself gemäß dem Block zurück.
(1..4).minmax {|a, b| -(a <=> b) } # => [4, 1]
Gibt [nil, nil] zurück, wenn
-
Der Anfangswert des Bereichs ist größer als sein Endwert.
(4..1).minmax # => [nil, nil] (4..1).minmax {|a, b| -(a <=> b) } # => [nil, nil]
-
Der Anfangswert eines exklusiven Bereichs ist gleich dem Endwert.
(1...1).minmax # => [nil, nil] (1...1).minmax {|a, b| -(a <=> b) } # => [nil, nil]
Löst eine Ausnahme aus, wenn self ein beginnloser oder endloser Bereich ist.
Source
static VALUE
range_overlap(VALUE range, VALUE other)
{
if (!rb_obj_is_kind_of(other, rb_cRange)) {
rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected Range)",
rb_class_name(rb_obj_class(other)));
}
VALUE self_beg = RANGE_BEG(range);
VALUE self_end = RANGE_END(range);
int self_excl = EXCL(range);
VALUE other_beg = RANGE_BEG(other);
VALUE other_end = RANGE_END(other);
int other_excl = EXCL(other);
if (empty_region_p(self_beg, other_end, other_excl)) return Qfalse;
if (empty_region_p(other_beg, self_end, self_excl)) return Qfalse;
if (!NIL_P(self_beg) && !NIL_P(other_beg)) {
VALUE cmp = rb_funcall(self_beg, id_cmp, 1, other_beg);
if (NIL_P(cmp)) return Qfalse;
/* if both begin values are equal, no more comparisons needed */
if (rb_cmpint(cmp, self_beg, other_beg) == 0) return Qtrue;
}
else if (NIL_P(self_beg) && !NIL_P(self_end) && NIL_P(other_beg) && !NIL_P(other_end)) {
VALUE cmp = rb_funcall(self_end, id_cmp, 1, other_end);
return RBOOL(!NIL_P(cmp));
}
if (empty_region_p(self_beg, self_end, self_excl)) return Qfalse;
if (empty_region_p(other_beg, other_end, other_excl)) return Qfalse;
return Qtrue;
}
Gibt true zurück, wenn range mit self überlappt, andernfalls false.
(0..2).overlap?(1..3) #=> true (0..2).overlap?(3..4) #=> false (0..).overlap?(..0) #=> true
Mit einem Nicht-Bereichs-Argument wird TypeError ausgelöst.
(1..3).overlap?(1) # TypeError
Gibt false zurück, wenn ein interner Aufruf von <=> nil zurückgibt; das heißt, die Operanden sind nicht vergleichbar.
(1..3).overlap?('a'..'d') # => false
Gibt false zurück, wenn self oder range leer ist. „Leerer Bereich“ bedeutet, dass sein Anfangswert größer oder für einen exklusiven Bereich gleich seinem Endwert ist.
(4..1).overlap?(2..3) # => false (4..1).overlap?(..3) # => false (4..1).overlap?(2..) # => false (2...2).overlap?(1..2) # => false (1..4).overlap?(3..2) # => false (..4).overlap?(3..2) # => false (1..).overlap?(3..2) # => false (1..2).overlap?(2...2) # => false
Gibt false zurück, wenn der Anfangswert eines von self und range größer oder gleich (wenn der andere ein exklusiver Bereich ist) dem Endwert des anderen ist.
(4..5).overlap?(2..3) # => false (4..5).overlap?(2...4) # => false (1..2).overlap?(3..4) # => false (1...3).overlap?(3..4) # => false
Gibt false zurück, wenn der Endwert eines von self und range größer oder gleich (wenn der andere ein exklusiver Bereich ist) dem Endwert des anderen ist.
(4..5).overlap?(2..3) # => false (4..5).overlap?(2...4) # => false (1..2).overlap?(3..4) # => false (1...3).overlap?(3..4) # => false
Beachten Sie, dass die Methode keine Annahmen darüber macht, dass der beginnlose Bereich tatsächlich leer ist, auch wenn seine Obergrenze der kleinstmögliche Wert seines Typs ist, sodass all dies true zurückgeben würde.
(...-Float::INFINITY).overlap?(...-Float::INFINITY) # => true (..."").overlap?(..."") # => true (...[]).overlap?(...[]) # => true
Auch wenn diese Bereiche effektiv leer sind (keine Zahl kann kleiner als -Float::INFINITY sein), werden sie dennoch mit sich selbst als überlappend betrachtet.
Verwandt: Range#cover?.
Source
static VALUE
range_reverse_each(VALUE range)
{
RETURN_SIZED_ENUMERATOR(range, 0, 0, range_enum_reverse_size);
VALUE beg = RANGE_BEG(range);
VALUE end = RANGE_END(range);
int excl = EXCL(range);
if (NIL_P(end)) {
rb_raise(rb_eTypeError, "can't iterate from %s",
rb_obj_classname(end));
}
if (FIXNUM_P(beg) && FIXNUM_P(end)) {
if (excl) {
if (end == LONG2FIX(FIXNUM_MIN)) return range;
end = rb_int_minus(end, INT2FIX(1));
}
range_reverse_each_fixnum_section(beg, end);
}
else if ((NIL_P(beg) || RB_INTEGER_TYPE_P(beg)) && RB_INTEGER_TYPE_P(end)) {
if (excl) {
end = rb_int_minus(end, INT2FIX(1));
}
range_reverse_each_positive_bignum_section(beg, end);
range_reverse_each_fixnum_section(beg, end);
range_reverse_each_negative_bignum_section(beg, end);
}
else {
return rb_call_super(0, NULL);
}
return range;
}
Mit einem gegebenen Block wird jedes Element von self in umgekehrter Reihenfolge an den Block übergeben.
a = [] (1..4).reverse_each {|element| a.push(element) } # => 1..4 a # => [4, 3, 2, 1] a = [] (1...4).reverse_each {|element| a.push(element) } # => 1...4 a # => [3, 2, 1]
Ohne einen gegebenen Block wird ein Enumerator zurückgegeben.
Source
static VALUE
range_size(VALUE range)
{
VALUE b = RANGE_BEG(range), e = RANGE_END(range);
if (RB_INTEGER_TYPE_P(b)) {
if (rb_obj_is_kind_of(e, rb_cNumeric)) {
return ruby_num_interval_step_size(b, e, INT2FIX(1), EXCL(range));
}
if (NIL_P(e)) {
return DBL2NUM(HUGE_VAL);
}
}
if (!discrete_object_p(b)) {
CANT_ITERATE_FROM(b);
}
return Qnil;
}
Gibt die Anzahl der Elemente in self zurück, wenn sowohl Anfangs- als auch Endwerte numerisch sind; andernfalls gibt es nil zurück.
(1..4).size # => 4 (1...4).size # => 3 (1..).size # => Infinity ('a'..'z').size # => nil
Wenn self nicht iterierbar ist, wird eine Ausnahme ausgelöst.
(0.5..2.5).size # TypeError (..1).size # TypeError
Verwandt: Range#count.
Source
static VALUE
range_step(int argc, VALUE *argv, VALUE range)
{
VALUE b, e, v, step;
int c, dir;
b = RANGE_BEG(range);
e = RANGE_END(range);
v = b;
const VALUE b_num_p = rb_obj_is_kind_of(b, rb_cNumeric);
const VALUE e_num_p = rb_obj_is_kind_of(e, rb_cNumeric);
// For backward compatibility reasons (conforming to behavior before 3.4), String/Symbol
// supports both old behavior ('a'..).step(1) and new behavior ('a'..).step('a')
// Hence the additional conversion/additional checks.
const VALUE str_b = rb_check_string_type(b);
const VALUE sym_b = SYMBOL_P(b) ? rb_sym2str(b) : Qnil;
if (rb_check_arity(argc, 0, 1))
step = argv[0];
else {
if (b_num_p || !NIL_P(str_b) || !NIL_P(sym_b) || (NIL_P(b) && e_num_p))
step = INT2FIX(1);
else
rb_raise(rb_eArgError, "step is required for non-numeric ranges");
}
const VALUE step_num_p = rb_obj_is_kind_of(step, rb_cNumeric);
if (step_num_p && b_num_p && rb_equal(step, INT2FIX(0))) {
rb_raise(rb_eArgError, "step can't be 0");
}
if (!rb_block_given_p()) {
// This code is allowed to create even beginless ArithmeticSequence, which can be useful,
// e.g., for array slicing:
// ary[(..-1) % 3]
if (step_num_p && ((b_num_p && (NIL_P(e) || e_num_p)) || (NIL_P(b) && e_num_p))) {
return rb_arith_seq_new(range, ID2SYM(rb_frame_this_func()), argc, argv,
range_step_size, b, e, step, EXCL(range));
}
// ...but generic Enumerator from beginless range is useless and probably an error.
if (NIL_P(b)) {
rb_raise(rb_eArgError, "#step for non-numeric beginless ranges is meaningless");
}
RETURN_SIZED_ENUMERATOR(range, argc, argv, 0);
}
if (NIL_P(b)) {
rb_raise(rb_eArgError, "#step iteration for beginless ranges is meaningless");
}
if (FIXNUM_P(b) && NIL_P(e) && FIXNUM_P(step)) {
/* perform summation of numbers in C until their reach Fixnum limit */
long i = FIX2LONG(b), unit = FIX2LONG(step);
do {
rb_yield(LONG2FIX(i));
i += unit; /* FIXABLE+FIXABLE never overflow */
} while (FIXABLE(i));
b = LONG2NUM(i);
/* then switch to Bignum API */
for (;; b = rb_big_plus(b, step))
rb_yield(b);
}
else if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) {
/* fixnums are special: summation is performed in C for performance */
long end = FIX2LONG(e);
long i, unit = FIX2LONG(step);
if (unit < 0) {
if (!EXCL(range))
end -= 1;
i = FIX2LONG(b);
while (i > end) {
rb_yield(LONG2NUM(i));
i += unit;
}
}
else {
if (!EXCL(range))
end += 1;
i = FIX2LONG(b);
while (i < end) {
rb_yield(LONG2NUM(i));
i += unit;
}
}
}
else if (b_num_p && step_num_p && ruby_float_step(b, e, step, EXCL(range), TRUE)) {
/* done */
}
else if (!NIL_P(str_b) && FIXNUM_P(step)) {
// backwards compatibility behavior for String only, when no step/Integer step is passed
// See discussion in https://bugs.ruby-lang.org/issues/18368
VALUE iter[2] = {INT2FIX(1), step};
if (NIL_P(e)) {
rb_str_upto_endless_each(str_b, step_i, (VALUE)iter);
}
else {
rb_str_upto_each(str_b, e, EXCL(range), step_i, (VALUE)iter);
}
}
else if (!NIL_P(sym_b) && FIXNUM_P(step)) {
// same as above: backward compatibility for symbols
VALUE iter[2] = {INT2FIX(1), step};
if (NIL_P(e)) {
rb_str_upto_endless_each(sym_b, sym_step_i, (VALUE)iter);
}
else {
rb_str_upto_each(sym_b, rb_sym2str(e), EXCL(range), sym_step_i, (VALUE)iter);
}
}
else if (NIL_P(e)) {
// endless range
for (;; v = rb_funcall(v, id_plus, 1, step))
rb_yield(v);
}
else if (b_num_p && step_num_p && r_less(step, INT2FIX(0)) < 0) {
// iterate backwards, for consistency with ArithmeticSequence
if (EXCL(range)) {
for (; r_less(e, v) < 0; v = rb_funcall(v, id_plus, 1, step))
rb_yield(v);
}
else {
for (; (c = r_less(e, v)) <= 0; v = rb_funcall(v, id_plus, 1, step)) {
rb_yield(v);
if (!c) break;
}
}
}
else if ((dir = r_less(b, e)) == 0) {
if (!EXCL(range)) {
rb_yield(v);
}
}
else if (dir == r_less(b, rb_funcall(b, id_plus, 1, step))) {
// Direction of the comparison. We use it as a comparison operator in cycle:
// if begin < end, the cycle performs while value < end (iterating forward)
// if begin > end, the cycle performs while value > end (iterating backward with
// a negative step)
// One preliminary addition to check the step moves iteration in the same direction as
// from begin to end; otherwise, the iteration should be empty.
if (EXCL(range)) {
for (; r_less(v, e) == dir; v = rb_funcall(v, id_plus, 1, step))
rb_yield(v);
}
else {
for (; (c = r_less(v, e)) == dir || c == 0; v = rb_funcall(v, id_plus, 1, step)) {
rb_yield(v);
if (!c) break;
}
}
}
return range;
}
Iteriert über die Elemente des Bereichs in Schritten von s. Die Iteration erfolgt durch den Operator +.
(0..6).step(2) { puts _1 } #=> 1..5 # Prints: 0, 2, 4, 6 # Iterate between two dates in step of 1 day (24 hours) (Time.utc(2022, 2, 24)..Time.utc(2022, 3, 1)).step(24*60*60) { puts _1 } # Prints: # 2022-02-24 00:00:00 UTC # 2022-02-25 00:00:00 UTC # 2022-02-26 00:00:00 UTC # 2022-02-27 00:00:00 UTC # 2022-02-28 00:00:00 UTC # 2022-03-01 00:00:00 UTC
Wenn + step den Wert verringert, wird die Iteration trotzdem durchgeführt, wenn begin höher als end ist.
(0..6).step(-2) { puts _1 } # Prints nothing (6..0).step(-2) { puts _1 } # Prints: 6, 4, 2, 0 (Time.utc(2022, 3, 1)..Time.utc(2022, 2, 24)).step(-24*60*60) { puts _1 } # Prints: # 2022-03-01 00:00:00 UTC # 2022-02-28 00:00:00 UTC # 2022-02-27 00:00:00 UTC # 2022-02-26 00:00:00 UTC # 2022-02-25 00:00:00 UTC # 2022-02-24 00:00:00 UTC
Wenn der Block nicht bereitgestellt wird und die Bereichsgrenzen und der Schritt Numeric sind, gibt die Methode Enumerator::ArithmeticSequence zurück.
(1..5).step(2) # => ((1..5).step(2)) (1.0..).step(1.5) #=> ((1.0..).step(1.5)) (..3r).step(1/3r) #=> ((..3/1).step((1/3)))
Enumerator::ArithmeticSequence kann weiter als Wertobjekt für die Iteration oder das Slicen von Sammlungen verwendet werden (siehe Array#[]). Es gibt eine praktische Methode % mit ähnlichem Verhalten wie step, um arithmetische Sequenzen ausdrucksstärker zu erzeugen.
# Same as (1..5).step(2) (1..5) % 2 # => ((1..5).%(2))
In einem allgemeinen Fall, wenn der Block nicht bereitgestellt wird, wird Enumerator zurückgegeben.
('a'..).step('b') #=> #<Enumerator: "a"..:step("b")> ('a'..).step('b').take(3) #=> ["a", "ab", "abb"]
Wenn s nicht bereitgestellt wird, wird es für Bereiche mit numerischem begin als 1 betrachtet.
(1..5).step { p _1 } # Prints: 1, 2, 3, 4, 5
Für Nicht-Numerische Bereiche ist das Fehlen eines Schritts ein Fehler.
(Time.utc(2022, 3, 1)..Time.utc(2022, 2, 24)).step { p _1 } # raises: step is required for non-numeric ranges (ArgumentError)
Aus Gründen der Abwärtskompatibilität unterstützt -Bereiche die Iteration sowohl mit einem Zeichenketten-Schritt als auch mit einem Ganzzahl-Schritt. Im letzteren Fall erfolgt die Iteration durch Berechnung der nächsten Werte mit StringString#succ.
('a'..'e').step(2) { p _1 } # Prints: a, c, e ('a'..'e').step { p _1 } # Default step 1; prints: a, b, c, d, e
Source
static VALUE
range_to_a(VALUE range)
{
if (NIL_P(RANGE_END(range))) {
rb_raise(rb_eRangeError, "cannot convert endless range to an array");
}
return rb_call_super(0, 0);
}
Gibt ein Array zurück, das die Elemente in self enthält, wenn es sich um eine endliche Sammlung handelt; löst andernfalls eine Ausnahme aus.
(1..4).to_a # => [1, 2, 3, 4] (1...4).to_a # => [1, 2, 3] ('a'..'d').to_a # => ["a", "b", "c", "d"]
Source
# File ext/json/lib/json/add/range.rb, line 51 def to_json(*args) as_json.to_json(*args) end
Gibt einen JSON-String zurück, der self repräsentiert
require 'json/add/range' puts (1..4).to_json puts (1...4).to_json puts ('a'..'d').to_json
Ausgabe
{"json_class":"Range","a":[1,4,false]}
{"json_class":"Range","a":[1,4,true]}
{"json_class":"Range","a":["a","d",false]}
Source
static VALUE
range_to_s(VALUE range)
{
VALUE str, str2;
str = rb_obj_as_string(RANGE_BEG(range));
str2 = rb_obj_as_string(RANGE_END(range));
str = rb_str_dup(str);
rb_str_cat(str, "...", EXCL(range) ? 3 : 2);
rb_str_append(str, str2);
return str;
}
Gibt eine Zeichenfolgendarstellung von self zurück, einschließlich begin.to_s und end.to_s.
(1..4).to_s # => "1..4" (1...4).to_s # => "1...4" (1..).to_s # => "1.." (..4).to_s # => "..4"
Beachten Sie, dass die Rückgaben von to_s und inspect unterschiedlich sein können.
('a'..'d').to_s # => "a..d" ('a'..'d').inspect # => "\"a\"..\"d\""
Verwandt: Range#inspect.
Source
static VALUE
range_to_set(int argc, VALUE *argv, VALUE range)
{
if (NIL_P(RANGE_END(range))) {
rb_raise(rb_eRangeError, "cannot convert endless range to a set");
}
return rb_call_super(argc, argv);
}
Gibt eine Menge zurück, die die Elemente in self enthält, wenn es sich um eine endliche Sammlung handelt; löst andernfalls eine Ausnahme aus.
(1..4).to_set # => Set[1, 2, 3, 4] (1...4).to_set # => Set[1, 2, 3] (1..).to_set # in 'Range#to_set': cannot convert endless range to a set (RangeError)