Class: Range
Relationships & Source Files | |
Super Chains via Extension / Inclusion / Inheritance | |
Instance Chain:
self,
::Enumerable
|
|
Inherits: | Object |
Defined in: | range.c |
Overview
A Range object represents a collection of values that are between given begin and end values.
You can create an Range object explicitly with:
-
A
range literal
:# 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"]
A range may be created using method .new:
# Ranges that by default include the given end value.
Range.new(1, 4).to_a # => [1, 2, 3, 4]
Range.new('a', 'd').to_a # => ["a", "b", "c", "d"]
# Ranges that use third argument exclude_end to exclude the given end value.
Range.new(1, 4, true).to_a # => [1, 2, 3]
Range.new('a', 'd', true).to_a # => ["a", "b", "c"]
Beginless Ranges
A beginless range has a definite end value, but a nil
begin value. Such a range includes all values up to the end value.
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
A beginless range may be used to slice an array:
a = [1, 2, 3, 4]
r = (..2) # => nil...2
a[r] # => [1, 2]
Method #each for a beginless range raises an exception.
Endless Ranges
An endless range has a definite begin value, but a nil
end value. Such a range includes all values from the begin value.
r = (1..) # => 1..
r.end # => nil
r.include?(50) # => true
Range.new(1, nil) # => 1..
The literal for an endless range may be written with either two dots or three. The range has the same elements, either way. But note that the two are not equal:
r0 = (1..) # => 1..
r1 = (1...) # => 1...
r0.begin == r1.begin # => true
r0.end == r1.end # => true
r0 == r1 # => false
An endless range may be used to slice an array:
a = [1, 2, 3, 4]
r = (2..) # => 2..
a[r] # => [3, 4]
Method #each for an endless range calls the given block indefinitely:
a = []
r = (1..)
r.each do |i|
a.push(i) if i.even?
break if i > 10
end
a # => [2, 4, 6, 8, 10]
Ranges and Other Classes
An object may be put into a range if its class implements instance method <=>
. Ruby core classes that do so include ::Array
, ::Complex
, ::File::Stat
, ::Float
, ::Integer
, ::Kernel
, ::Module
, ::Numeric
, ::Rational
, ::String
, ::Symbol
, and ::Time
.
Example:
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
A range can be iterated over only if its elements implement instance method succ
. Ruby core classes that do so include ::Integer
, ::String
, and ::Symbol
(but not the other classes mentioned above).
Iterator methods include:
-
Included from module Enumerable:
#each_entry
,#each_with_index
, #each_with_object, #each_slice, #each_cons, and #reverse_each.
Example:
a = []
(1..4).each {|i| a.push(i) }
a # => [1, 2, 3, 4]
Ranges and User-Defined Classes
A user-defined class that is to be used in a range must implement instance <=>
; see Integer#<=>
. To make iteration available, it must also implement instance method succ
; see Integer#succ.
The class below implements both <=>
and succ
, and so can be used both to construct ranges and to iterate over them. Note that the ::Comparable
module is included so the #== method is defined in terms of <=>
.
# 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
What’s Here
First, what’s elsewhere. Class Range:
-
Inherits from [class Object](Object.html#class-Object-label-What-27s+Here).
-
Includes [module Enumerable](Enumerable.html#module-Enumerable-label-What-27s+Here), which provides dozens of additional methods.
Here, class Range provides methods that are useful for:
Methods for Creating a Range
- ::new
-
Returns a new range.
Methods for Querying
- #begin
-
Returns the begin value given for
self
.
- #bsearch
-
Returns an element from
self
selected by a binary search.
- #count
-
Returns a count of elements in
self
.
- #end
-
Returns the end value given for
self
.
- #exclude_end?
-
Returns whether the end object is excluded.
- #first
-
Returns the first elements of
self
.
- #hash
-
Returns the integer hash code.
- #last
-
Returns the last elements of
self
.
- #max
-
Returns the maximum values in
self
.
- #min
-
Returns the minimum values in
self
.
- #minmax
-
Returns the minimum and maximum values in
self
.
- #size
-
Returns the count of elements in
self
.
Methods for Comparing
#==
-
Returns whether a given object is equal to
self
(uses #==).
- #===
-
Returns whether the given object is between the begin and end values.
- #cover?
-
Returns whether a given object is within
self
.
- #eql?
-
Returns whether a given object is equal to
self
(uses #eql?).
-
is an element of self.
Methods for Iterating
- #%
-
Requires argument
n
; calls the block with eachn
-th element ofself
.
- #each
-
Calls the block with each element of
self
.
- #step
-
Takes optional argument
n
(defaults to 1);calls the block with each n-th element of self.
Methods for Converting
Class Method Summary
- .new(begin, end, exclude_end = false) ⇒ Range constructor
Instance Attribute Summary
-
#exclude_end? ⇒ Boolean
readonly
Returns
true
ifself
excludes its end value;false
otherwise:
Instance Method Summary
-
#%(n) {|element| ... } ⇒ self
Iterates over the elements of
self
. -
#==(other) ⇒ Boolean
Returns
true
if and only if: -
#===(object) ⇒ Boolean
Returns
true
ifobject
is betweenself.begin
andself.end
. -
#begin ⇒ Object
Returns the object that defines the beginning of
self
. -
#bsearch {|obj| ... } ⇒ value
Returns an element from
self
selected by a binary search. -
#count ⇒ Integer
Returns the count of elements, based on an argument or block criterion, if given.
-
#cover?(object) ⇒ Boolean
Returns
true
if the given argument is withinself
,false
otherwise. -
#each {|element| ... } ⇒ self
With a block given, passes each element of
self
to the block: -
#end ⇒ Object
Returns the object that defines the end of
self
. -
#entries ⇒ Array
Alias for #to_a.
-
#eql?(other) ⇒ Boolean
Returns
true
if and only if: -
#first ⇒ Object
With no argument, returns the first element of
self
, if it exists: -
#hash ⇒ Integer
Returns the integer hash value for
self
. -
#include?(object) ⇒ Boolean
Alias for #member?.
-
#inspect ⇒ String
Returns a string representation of
self
, includingbegin.inspect
andend.inspect
: -
#last ⇒ Object
With no argument, returns the last element of
self
, if it exists: -
#max ⇒ Object
Returns the maximum value in
self
, using method<=>
or a given block for comparison. -
#include?(object) ⇒ Boolean
(also: #include?)
Returns
true
ifobject
is an element ofself
,false
otherwise: -
#min ⇒ Object
Returns the minimum value in
self
, using method<=>
or a given block for comparison. -
#minmax ⇒ Array, Object
Returns a 2-element array containing the minimum and maximum value in
self
, either according to comparison method<=>
or a given block. -
#size ⇒ non_negative_integer, ...
Returns the count of elements in
self
if both begin and end values are numeric; otherwise, returnsnil
: -
#step(n = 1) {|element| ... } ⇒ self
Iterates over the elements of
self
. -
#to_a ⇒ Array
(also: #entries)
Returns an array containing the elements in
self
, if a finite collection; raises an exception otherwise. -
#to_s ⇒ String
Returns a string representation of
self
, includingbegin.to_s
andend.to_s
: - #initialize_copy(orig) Internal use only
::Enumerable
- Included
#all? | Returns whether every element meets a given criterion. |
#any? | Returns whether any element meets a given criterion. |
#chain | Returns an enumerator object generated from this enumerator and given enumerables. |
#chunk | Each element in the returned enumerator is a 2-element array consisting of: |
#chunk_while | Creates an enumerator for each chunked elements. |
#collect | Alias for Enumerable#map. |
#collect_concat | Alias for Enumerable#flat_map. |
#compact | Returns an array of all non- |
#count | Returns the count of elements, based on an argument or block criterion, if given. |
#cycle | When called with positive integer argument |
#detect | Alias for Enumerable#find. |
#drop | For positive integer |
#drop_while | Calls the block with successive elements as long as the block returns a truthy value; returns an array of all elements after that point: |
#each_cons | Calls the block with each successive overlapped |
#each_entry | Calls the given block with each element, converting multiple values from yield to an array; returns |
#each_slice | Calls the block with each successive disjoint |
#each_with_index | With a block given, calls the block with each element and its index; returns |
#each_with_object | Calls the block once for each element, passing both the element and the given object: |
#entries | Alias for Enumerable#to_a. |
#filter | Returns an array containing elements selected by the block. |
#filter_map | Returns an array containing truthy elements returned by the block. |
#find | Returns the first element for which the block returns a truthy value. |
#find_all | Alias for Enumerable#filter. |
#find_index | Returns the index of the first element that meets a specified criterion, or |
#first | Returns the first element or elements. |
#flat_map | Returns an array of flattened objects returned by the block. |
#grep | Returns an array of objects based elements of |
#grep_v | Returns an array of objects based on elements of |
#group_by | With a block given returns a hash: |
#include? | Alias for Enumerable#member?. |
#inject | Returns an object formed from operands via either: |
#lazy | Returns an |
#map | Returns an array of objects returned by the block. |
#max | Returns the element with the maximum element according to a given criterion. |
#max_by | Returns the elements for which the block returns the maximum values. |
#member? | Returns whether for any element |
#min | Returns the element with the minimum element according to a given criterion. |
#min_by | Returns the elements for which the block returns the minimum values. |
#minmax | Returns a 2-element array containing the minimum and maximum elements according to a given criterion. |
#minmax_by | Returns a 2-element array containing the elements for which the block returns minimum and maximum values: |
#none? | Returns whether no element meets a given criterion. |
#one? | Returns whether exactly one element meets a given criterion. |
#partition | With a block given, returns an array of two arrays: |
#reduce | Alias for Enumerable#inject. |
#reject | Returns an array of objects rejected by the block. |
#reverse_each | With a block given, calls the block with each element, but in reverse order; returns |
#select | Alias for Enumerable#filter. |
#slice_after | Creates an enumerator for each chunked elements. |
#slice_before | With argument |
#slice_when | Creates an enumerator for each chunked elements. |
#sort | Returns an array containing the sorted elements of |
#sort_by | With a block given, returns an array of elements of |
#sum | With no block given, returns the sum of |
#take | For non-negative integer |
#take_while | Calls the block with successive elements as long as the block returns a truthy value; returns an array of all elements up to that point: |
#tally | Returns a hash containing the counts of equal elements: |
#to_a | Returns an array containing the items in |
#to_h | When |
#uniq | With no block, returns a new array containing only unique elements; the array has no two elements |
#zip | With no block given, returns a new array |
Constructor Details
.new(begin, end, exclude_end = false) ⇒ Range
Returns a new range based on the given objects #begin and #end. Optional argument exclude_end
determines whether object #end is included as the last object in the range:
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"]
# File 'range.c', line 100
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; }
Instance Attribute Details
#exclude_end? ⇒ Boolean
(readonly)
# File 'range.c', line 132
static VALUE range_exclude_end_p(VALUE range) { return RBOOL(EXCL(range)); }
Instance Method Details
#%(n) {|element| ... } ⇒ self
#%(n) ⇒ Enumerator
self
#%(n) ⇒ Enumerator
Iterates over the elements of self
.
With a block given, calls the block with selected elements of the range; returns self
:
a = []
(1..5).%(2) {|element| a.push(element) } # => 1..5
a # => [1, 3, 5]
a = []
('a'..'e').%(2) {|element| a.push(element) } # => "a".."e"
a # => ["a", "c", "e"]
With no block given, returns an enumerator, which will be of class ::Enumerator::ArithmeticSequence
if self
is numeric; otherwise of class ::Enumerator
:
e = (1..5) % 2 # => ((1..5).%(2))
e.class # => Enumerator::ArithmeticSequence
('a'..'e') % 2 # => #<Enumerator: ...>
Related: #step.
# File 'range.c', line 568
static VALUE range_percent_step(VALUE range, VALUE step) { return range_step(1, &step, range); }
#==(other) ⇒ Boolean
Returns true
if and only if:
-
other
is a range. -
other.begin == self.begin
. -
other.end == self.end
. -
other.exclude_end? == self.exclude_end?
.
Otherwise returns false
.
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
Note that even with the same argument, the return values of #==
and #eql? can differ:
(1..2) == (1..2.0) # => true
(1..2).eql? (1..2.0) # => false
Related: #eql?.
# File 'range.c', line 182
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); }
#===(object) ⇒ Boolean
Returns true
if object
is between self.begin
and self.end
. false
otherwise:
(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
A case statement uses method ===
, and 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"
# File 'range.c', line 1721
static VALUE range_eqq(VALUE range, VALUE val) { VALUE ret = range_include_internal(range, val, 1); if (ret != Qundef) return ret; return r_cover_p(range, RANGE_BEG(range), RANGE_END(range), val); }
#begin ⇒ Object
# File 'range.c', line 1009
static VALUE range_begin(VALUE range) { return RANGE_BEG(range); }
#bsearch {|obj| ... } ⇒ value
Returns an element from self
selected by a binary search.
See Binary Searching
.
# File 'range.c', line 682
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) * as well as the fact that -1/2 can be 0 or -1 in C89. * * 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) \ do { \ RETURN_ENUMERATOR(range, 0, 0); \ if (EXCL(range)) high--; \ org_high = high; \ while (low < high) { \ mid = ((high < 0) == (low < 0)) ? low + ((high - low) / 2) \ : (low < -high) ? -((-1 - low - high)/2 + 1) : (low + high) / 2; \ BSEARCH_CHECK(conv(mid)); \ if (smaller) { \ high = mid; \ } \ else { \ low = mid + 1; \ } \ } \ if (low == org_high) { \ BSEARCH_CHECK(conv(low)); \ if (!smaller) return Qnil; \ } \ return satisfied; \ } while (0) beg = RANGE_BEG(range); end = RANGE_END(range); if (FIXNUM_P(beg) && FIXNUM_P(end)) { long low = FIX2LONG(beg); long high = FIX2LONG(end); long mid, org_high; BSEARCH(INT2FIX); } #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, org_high; BSEARCH(int64_as_double_to_num); } #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) { return bsearch_integer_range(beg, mid, 0); } diff = rb_funcall(diff, '*', 1, LONG2FIX(2)); } } 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) { return bsearch_integer_range(mid, end, 0); } diff = rb_funcall(diff, '*', 1, LONG2FIX(2)); } } else { rb_raise(rb_eTypeError, "can't do binary search for %s", rb_obj_classname(beg)); } return range; }
Returns the count of elements, based on an argument or block criterion, if given.
With no argument and no block given, returns the number of elements:
(1..4).count # => 4
(1...4).count # => 3
('a'..'d').count # => 4
('a'...'d').count # => 3
(1..).count # => Infinity
(..4).count # => Infinity
With argument object
, returns the number of object
found in self
, which will usually be zero or one:
(1..4).count(2) # => 1
(1..4).count(5) # => 0
(1..4).count('a') # => 0
With a block given, calls the block with each element; returns the number of elements for which the block returns a truthy value:
(1..4).count {|element| element < 3 } # => 2
Related: #size.
# File 'range.c', line 2076
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); } else if (NIL_P(RANGE_END(range))) { /* We are confident that the answer is Infinity. */ return DBL2NUM(HUGE_VAL); } else if (NIL_P(RANGE_BEG(range))) { /* We are confident that the answer is Infinity. */ return DBL2NUM(HUGE_VAL); } else { return rb_call_super(argc, argv); } }
#cover?(object) ⇒ Boolean
#cover?(range) ⇒ Boolean
Boolean
#cover?(range) ⇒ Boolean
Returns true
if the given argument is within self
, false
otherwise.
With non-range argument object, evaluates with {<=} and {<}.
For range self with included end value (<tt>#exclude_end? == false</tt>),
evaluates thus:
self.begin <= object <= self.end
Examples:
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
For range r with excluded end value (<tt>#exclude_end? == true</tt>),
evaluates thus:
r.begin <= object < r.end
Examples:
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
With range argument range, compares the first and last
elements of self and range:
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
If begin and end are numeric, #cover? behaves like #include?
(1..3).cover?(1.5) # => true
(1..3).include?(1.5) # => true
But when not numeric, the two methods may differ:
('a'..'d').cover?('cc') # => true
('a'..'d').include?('cc') # => false
Returns false if either:
- The begin value of self is larger than its end value.
- An internal call to {<=>} returns nil;
that is, the operands are not comparable.
Beginless ranges cover all values of the same type before the end, excluding the end for exclusive ranges. Beginless ranges cover ranges that end before the end of the beginless range, or at the end of the beginless range for inclusive ranges.
(..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
Endless ranges cover all values of the same type after the beginning. Endless exclusive ranges do not cover endless inclusive ranges.
(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
Ranges that are both beginless and endless cover all values and ranges, and return true for all arguments, with the exception that beginless and endless exclusive ranges do not cover endless inclusive ranges.
(nil...).cover?(Object.new) # => true
(nil...).cover?(nil...) # => true
(nil..).cover?(nil...) # => true
(nil...).cover?(nil..) # => false
(nil...).cover?(1..) # => false
Related: Range#include?.
# File 'range.c', line 1935
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); }
#each {|element| ... } ⇒ self
#each ⇒ Enumerator
self
#each ⇒ Enumerator
With a block given, passes each element of self
to the block:
a = []
(1..4).each {|element| a.push(element) } # => 1..4
a # => [1, 2, 3, 4]
Raises an exception unless self.first.respond_to?(:succ)
.
With no block given, returns an enumerator.
# File 'range.c', line 903
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; }
#end ⇒ Object
# File 'range.c', line 1030
static VALUE range_end(VALUE range) { return RANGE_END(range); }
Alias for #to_a.
#eql?(other) ⇒ Boolean
Returns true
if and only if:
-
other
is a range. -
other.begin eql? self.begin
. -
other.end eql? self.end
. -
other.exclude_end? == self.exclude_end?
.
Otherwise returns false
.
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
Note that even with the same argument, the return values of #== and #eql?
can differ:
(1..2) == (1..2.0) # => true
(1..2).eql? (1..2.0) # => false
Related: #==.
# File 'range.c', line 250
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); }
With no argument, returns the first element of self
, if it exists:
(1..4).first # => 1
('a'..'d').first # => "a"
With non-negative integer argument n
given, returns the first n
elements in an array:
(1..10).first(3) # => [1, 2, 3]
(1..10).first(0) # => []
(1..4).first(50) # => [1, 2, 3, 4]
Raises an exception if there is no first element:
(..4).first # Raises RangeError
# File 'range.c', line 1074
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]; }
#hash ⇒ Integer
Returns the integer hash value for self
. Two range objects r0
and r1
have the same hash value if and only if r0.eql?(r1)
.
Related: #eql?, Object#hash.
# File 'range.c', line 271
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); }
#include?(object) ⇒ Boolean
#include?(object) ⇒ Boolean
Boolean
#include?(object) ⇒ Boolean
Alias for #member?.
#initialize_copy(orig)
# File 'range.c', line 112
static VALUE range_initialize_copy(VALUE range, VALUE orig) { range_modify(range); rb_struct_init_copy(range, orig); return range; }
#inspect ⇒ String
Returns a string representation of self
, including begin.inspect
and end.inspect
:
(1..4).inspect # => "1..4"
(1...4).inspect # => "1...4"
(1..).inspect # => "1.."
(..4).inspect # => "..4"
Note that returns from #to_s and #inspect
may differ:
('a'..'d').to_s # => "a..d"
('a'..'d').inspect # => "\"a\"..\"d\""
Related: #to_s.
# File 'range.c', line 1674
static VALUE range_inspect(VALUE range) { return rb_exec_recursive(inspect_range, range, 0); }
With no argument, returns the last element of self
, if it exists:
(1..4).last # => 4
('a'..'d').last # => "d"
Note that last
with no argument returns the end element of self
even if #exclude_end? is true
:
(1...4).last # => 4
('a'...'d').last # => "d"
With non-negative integer argument n
given, returns the last n
elements in an array:
(1..10).last(3) # => [8, 9, 10]
(1..10).last(0) # => []
(1..4).last(50) # => [1, 2, 3, 4]
Note that last
with argument does not return the end element of self
if #exclude_end? it true
:
(1...4).last(3) # => [1, 2, 3]
('a'...'d').last(3) # => ["a", "b", "c"]
Raises an exception if there is no last element:
(1..).last # Raises RangeError
# File 'range.c', line 1180
static VALUE range_last(int argc, VALUE *argv, VALUE range) { VALUE b, e; 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); b = RANGE_BEG(range); e = RANGE_END(range); if (RB_INTEGER_TYPE_P(b) && RB_INTEGER_TYPE_P(e) && RB_LIKELY(rb_method_basic_definition_p(rb_cRange, idEach))) { return rb_int_range_last(argc, argv, range); } return rb_ary_last(argc, argv, rb_Array(range)); }
Returns the maximum value in self
, using method <=>
or a given block for comparison.
With no argument and no block given, returns the maximum-valued element of self
.
(1..4).max # => 4
('a'..'d').max # => "d"
(-4..-1).max # => -1
With non-negative integer argument n
given, and no block given, returns the n
maximum-valued elements of self
in an array:
(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]
If a block is given, it is called:
-
First, with the first two element of
self
. -
Then, sequentially, with the so-far maximum value and the next element of
self
.
To illustrate:
(1..4).max {|a, b| p [a, b]; a <=> b } # => 4
Output:
[2, 1]
[3, 2]
[4, 3]
With no argument and a block given, returns the return value of the last call to the block:
(1..4).max {|a, b| -(a <=> b) } # => 1
With non-negative integer argument n
given, and a block given, returns the return values of the last n
calls to the block in an array:
(1..4).max(2) {|a, b| -(a <=> b) } # => [1, 2]
(1..4).max(50) {|a, b| -(a <=> b) } # => [1, 2, 3, 4]
Returns an empty array if n
is zero:
(1..4).max(0) # => []
(1..4).max(0) {|a, b| -(a <=> b) } # => []
Returns nil
or an empty array if:
-
The begin value of the range is larger than the end value:
(4..1).max # => nil (4..1).max(2) # => [] (4..1).max {|a, b| -(a <=> b) } # => nil (4..1).max(2) {|a, b| -(a <=> b) } # => []
-
The begin value of an exclusive range is equal to the end value:
(1...1).max # => nil (1...1).max(2) # => [] (1...1).max {|a, b| -(a <=> b) } # => nil (1...1).max(2) {|a, b| -(a <=> b) } # => []
Raises an exception if either:
-
self
is a endless range:(1..)
. -
A block is given and
self
is a beginless range.
# File 'range.c', line 1390
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) || argc) { 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 { struct cmp_opt_data cmp_opt = { 0, 0 }; int c = NIL_P(b) ? -1 : OPTIMIZED_CMP(b, e, cmp_opt); 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 (!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_funcall(e, '-', 1, INT2FIX(1)); } return e; } }
#include?(object) ⇒ Boolean
Also known as: #include?
Returns true
if object
is an element of self
, false
otherwise:
(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
If begin and end are numeric, #include? behaves like #cover?
(1..3).include?(1.5) # => true
(1..3).cover?(1.5) # => true
But when not numeric, the two methods may differ:
('a'..'d').include?('cc') # => false
('a'..'d').cover?('cc') # => true
Related: #cover?.
member?
is an alias for #include?.
# File 'range.c', line 1761
static VALUE range_include(VALUE range, VALUE val) { VALUE ret = range_include_internal(range, val, 0); if (ret != Qundef) return ret; return rb_call_super(1, &val); }
Returns the minimum value in self
, using method <=>
or a given block for comparison.
With no argument and no block given, returns the minimum-valued element of self
.
(1..4).min # => 1
('a'..'d').min # => "a"
(-4..-1).min # => -4
With non-negative integer argument n
given, and no block given, returns the n
minimum-valued elements of self
in an array:
(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]
If a block is given, it is called:
-
First, with the first two element of
self
. -
Then, sequentially, with the so-far minimum value and the next element of
self
.
To illustrate:
(1..4).min {|a, b| p [a, b]; a <=> b } # => 1
Output:
[2, 1]
[3, 1]
[4, 1]
With no argument and a block given, returns the return value of the last call to the block:
(1..4).min {|a, b| -(a <=> b) } # => 4
With non-negative integer argument n
given, and a block given, returns the return values of the last n
calls to the block in an array:
(1..4).min(2) {|a, b| -(a <=> b) } # => [4, 3]
(1..4).min(50) {|a, b| -(a <=> b) } # => [4, 3, 2, 1]
Returns an empty array if n
is zero:
(1..4).min(0) # => []
(1..4).min(0) {|a, b| -(a <=> b) } # => []
Returns nil
or an empty array if:
-
The begin value of the range is larger than the end value:
(4..1).min # => nil (4..1).min(2) # => [] (4..1).min {|a, b| -(a <=> b) } # => nil (4..1).min(2) {|a, b| -(a <=> b) } # => []
-
The begin value of an exclusive range is equal to the end value:
(1...1).min # => nil (1...1).min(2) # => [] (1...1).min {|a, b| -(a <=> b) } # => nil (1...1).min(2) {|a, b| -(a <=> b) } # => []
Raises an exception if either:
-
self
is a beginless range:(..4)
. -
A block is given and
self
is an endless range.
# File 'range.c', line 1281
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 { struct cmp_opt_data cmp_opt = { 0, 0 }; VALUE b = RANGE_BEG(range); VALUE e = RANGE_END(range); int c = NIL_P(e) ? -1 : OPTIMIZED_CMP(b, e, cmp_opt); if (c > 0 || (c == 0 && EXCL(range))) return Qnil; return b; } }
Returns a 2-element array containing the minimum and maximum value in self
, either according to comparison method <=>
or a given block.
With no block given, returns the minimum and maximum values, using <=>
for comparison:
(1..4).minmax # => [1, 4]
(1...4).minmax # => [1, 3]
('a'..'d').minmax # => ["a", "d"]
(-4..-1).minmax # => [-4, -1]
With a block given, the block must return an integer:
-
Negative if
a
is smaller thanb
. -
Zero if
a
andb
are equal. -
Positive if
a
is larger thanb
.
The block is called self.size
times to compare elements; returns a 2-element ::Array
containing the minimum and maximum values from self
, per the block:
(1..4).minmax {|a, b| -(a <=> b) } # => [4, 1]
Returns [nil, nil]
if:
-
The begin value of the range is larger than the end value:
(4..1).minmax # => [nil, nil] (4..1).minmax {|a, b| -(a <=> b) } # => [nil, nil]
-
The begin value of an exclusive range is equal to the end value:
(1...1).minmax # => [nil, nil] (1...1).minmax {|a, b| -(a <=> b) } # => [nil, nil]
Raises an exception if self
is a beginless or an endless range.
# File 'range.c', line 1477
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) ); }
#size ⇒ non_negative_integer
, ...
Returns the count of elements in self
if both begin and end values are numeric; otherwise, returns nil
:
(1..4).size # => 4
(1...4).size # => 3
(1..).size # => Infinity
('a'..'z').size #=> nil
Related: #count.
# File 'range.c', line 806
static VALUE range_size(VALUE range) { VALUE b = RANGE_BEG(range), e = RANGE_END(range); if (rb_obj_is_kind_of(b, rb_cNumeric)) { 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); } } else if (NIL_P(b)) { return DBL2NUM(HUGE_VAL); } return Qnil; }
#step(n = 1) {|element| ... } ⇒ self
#step(n = 1) ⇒ Enumerator
self
#step(n = 1) ⇒ Enumerator
Iterates over the elements of self
.
With a block given and no argument, calls the block each element of the range; returns self
:
a = []
(1..5).step {|element| a.push(element) } # => 1..5
a # => [1, 2, 3, 4, 5]
a = []
('a'..'e').step {|element| a.push(element) } # => "a".."e"
a # => ["a", "b", "c", "d", "e"]
With a block given and a positive integer argument n
given, calls the block with element 0
, element n
, element 2n
, and so on:
a = []
(1..5).step(2) {|element| a.push(element) } # => 1..5
a # => [1, 3, 5]
a = []
('a'..'e').step(2) {|element| a.push(element) } # => "a".."e"
a # => ["a", "c", "e"]
With no block given, returns an enumerator, which will be of class ::Enumerator::ArithmeticSequence
if self
is numeric; otherwise of class ::Enumerator
:
e = (1..5).step(2) # => ((1..5).step(2))
e.class # => Enumerator::ArithmeticSequence
('a'..'e').step # => #<Enumerator: ...>
Related: #%.
# File 'range.c', line 438
static VALUE range_step(int argc, VALUE *argv, VALUE range) { VALUE b, e, step, tmp; b = RANGE_BEG(range); e = RANGE_END(range); step = (!rb_check_arity(argc, 0, 1) ? INT2FIX(1) : argv[0]); if (!rb_block_given_p()) { if (!rb_obj_is_kind_of(step, rb_cNumeric)) { step = rb_to_int(step); } if (rb_equal(step, INT2FIX(0))) { rb_raise(rb_eArgError, "step can't be 0"); } 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); if ((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)); } RETURN_SIZED_ENUMERATOR(range, argc, argv, range_step_size); } step = check_step_domain(step); VALUE iter[2] = {INT2FIX(1), step}; if (FIXNUM_P(b) && NIL_P(e) && FIXNUM_P(step)) { long i = FIX2LONG(b), unit = FIX2LONG(step); do { rb_yield(LONG2FIX(i)); i += unit; /* FIXABLE+FIXABLE never overflow */ } while (FIXABLE(i)); b = LONG2NUM(i); for (;; b = rb_big_plus(b, step)) rb_yield(b); } else if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) { /* fixnums are special */ long end = FIX2LONG(e); long i, unit = FIX2LONG(step); if (!EXCL(range)) end += 1; i = FIX2LONG(b); while (i < end) { rb_yield(LONG2NUM(i)); if (i + unit < i) break; i += unit; } } else if (SYMBOL_P(b) && (NIL_P(e) || SYMBOL_P(e))) { /* symbols are special */ b = rb_sym2str(b); if (NIL_P(e)) { rb_str_upto_endless_each(b, sym_step_i, (VALUE)iter); } else { rb_str_upto_each(b, rb_sym2str(e), EXCL(range), sym_step_i, (VALUE)iter); } } else if (ruby_float_step(b, e, step, EXCL(range), TRUE)) { /* done */ } else if (rb_obj_is_kind_of(b, rb_cNumeric) || !NIL_P(rb_check_to_integer(b, "to_int")) || !NIL_P(rb_check_to_integer(e, "to_int"))) { ID op = EXCL(range) ? '<' : idLE; VALUE v = b; int i = 0; while (NIL_P(e) || RTEST(rb_funcall(v, op, 1, e))) { rb_yield(v); i++; v = rb_funcall(b, '+', 1, rb_funcall(INT2NUM(i), '*', 1, step)); } } else { tmp = rb_check_string_type(b); if (!NIL_P(tmp)) { b = tmp; if (NIL_P(e)) { rb_str_upto_endless_each(b, step_i, (VALUE)iter); } else { rb_str_upto_each(b, e, EXCL(range), step_i, (VALUE)iter); } } else { if (!discrete_object_p(b)) { rb_raise(rb_eTypeError, "can't iterate from %s", rb_obj_classname(b)); } range_each_func(range, step_i, (VALUE)iter); } } return range; }
#to_a ⇒ Array Also known as: #entries
Returns an array containing the elements in self
, if a finite collection; raises an exception otherwise.
(1..4).to_a # => [1, 2, 3, 4]
(1...4).to_a # => [1, 2, 3]
('a'..'d').to_a # => ["a", "b", "c", "d"]
#entries is an alias for to_a
.
# File 'range.c', line 839
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); }
#to_s ⇒ String
Returns a string representation of self
, including begin.to_s
and end.to_s
:
(1..4).to_s # => "1..4"
(1...4).to_s # => "1...4"
(1..).to_s # => "1.."
(..4).to_s # => "..4"
Note that returns from #to_s
and #inspect may differ:
('a'..'d').to_s # => "a..d"
('a'..'d').inspect # => "\"a\"..\"d\""
Related: #inspect.
# File 'range.c', line 1615
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; }