Class: Range
- Defined in:
- lib/rmtools/enumerable/range.rb,
lib/rmtools/rand/range.rb,
lib/rmtools/conversions/ip.rb,
lib/rmtools/conversions/numeric.rb
Overview
Range in Ruby can have at least 2 meanings: 1) interval of real numbers (0…2).include? 1.6 # => true 2) lazy list of array indices (included integers):
- 0,1,2,3,4,5][1..4
-
# => [1, 2, 3, 4]
There is some basic problems. 1) For the first way of using, Range doesn’t have Set operations. Further more Range can not be complex. There is “intervals” gem that partially solves these problems, but it’s arithmetic is not Set compatible: -Interval # => Interval[-2, -1] instead of # => Interval[[-Inf, -2], [-1, +Inf]] 2) Hardly we can use Range second way, when it defined by non-integers:
- 0,1,2,3,4,5][1.9..4
-
# => [1, 2, 3, 4]
(1.9…4.1).include? 4 # => true, AND (1.9…4.1).include? 1 # => false, BUT
- 0,1,2,3,4,5][1.9…4.1
-
# => [1, 2, 3]
A domain of the present extension is Set operations with ranges considered as lazy lists of integers. The present extension is solving the second problem, yet
-
saving the capability of a Range syntactic sugar;
-
does exactly extend and not modify the Range behaviour.
These methods support only numeric ranges, it won’t work with chars and datetime borders, though I’ll make a support for the Date and Time in a future version.
Instance Method Summary collapse
-
#&(range) ⇒ Object
Intersection.
-
#-(range) ⇒ Object
On the basis of #-@ for non-integers, (0..3) - (1..2) (0..3) - (0.5..2.1) => XRange(0..0, 3..3).
-
#-@ ⇒ Object
Unfortunately, Range’s start point can not be excluded, thus there is no *true inversion* of a range with included end.
-
#<<(i) ⇒ Object
Move range as interval left.
- #<=>(range) ⇒ Object
-
#>>(i) ⇒ Object
Move range as interval right.
-
#^(range) ⇒ Object
Diff.
- #b ⇒ Object
-
#center ⇒ Object
(also: #avg)
Average.
-
#empty? ⇒ Boolean
Include any integer?.
- #evens ⇒ Object
-
#include?(number_or_range) ⇒ Boolean
#include? corresponds with Ruby’s default one, which considers a range as an interval (0..1).include? 1.0 1.in 0..1 => true and (0…1.0).include? 1.0 => false.
-
#include_end ⇒ Object
End inclusion need to universalize ranges for use in XRange list.
- #include_number? ⇒ Object
- #included_end ⇒ Object
-
#integerize ⇒ Object
Simplify a range to in-domain equivalent with integer edges.
-
#integers ⇒ Object
(also: #to_is)
Significant content of a range then.
- #mask_ip ⇒ Object
-
#max(&fun) ⇒ Object
maximum of monotone function definition interval.
-
#min(&fun) ⇒ Object
minimum of monotone function definition interval.
- #odds ⇒ Object
- #rand ⇒ Object
- #randseg ⇒ Object
-
#size ⇒ Object
Represent a count of integers that range include and not real interval length (0..0).size => 1 (equivalent list of one 0) (0…0).size => 0 (equivalent empty list) (0.3..0.5).size => 0 (there is no integer between 0.3 and 0.5) (0.9…1.1).size => 1 (equivalent list of one 1 which is between 0.9 and 1.1) (2..1).size => 0 (such a range just does’t make sense).
-
#sum ⇒ Object
Sum of integers in a range.
-
#x?(range, pretend_not_exclude = false) ⇒ Boolean
(also: #intersects?)
Does these ranges have at least one common point? (0..1).x? 1..2 (1…2).x? 0..1 (0..3).x? 1..2 (1..2).x? 0..3 => true (0..1.4).x? 1.5..2 (0…1).x? 1..2 (2..3).x? 0..1 => false.
-
#|(range) ⇒ Object
Union (1..3) | (2..4) => 1..4 (1…2) | (2..4) => 1..4 (1..2) | (3..4) => XRange(1..2, 3..4) A result will be inadequate if any range is not integered and excludes end.
Instance Method Details
#&(range) ⇒ Object
Intersection
105 106 107 108 109 110 |
# File 'lib/rmtools/enumerable/range.rb', line 105 def &(range) return range & self if range.is XRange fst = [first, range.first].max lst = [included_end, range.included_end].min fst > lst ? nil : fst..lst end |
#-(range) ⇒ Object
On the basis of #-@ for non-integers, (0..3) - (1..2) (0..3) - (0.5..2.1)
> XRange(0..0, 3..3)
116 117 118 |
# File 'lib/rmtools/enumerable/range.rb', line 116 def -(range) self & -range end |
#-@ ⇒ Object
Unfortunately, Range’s start point can not be excluded, thus there is no *true inversion* of a range with included end. Though, is this domain we can “integerize” range, then -(1..2) -(0.5..2.1) (i.e. all excluding these indices: [1, 2])
> XRange(-∞..0, 3..+∞)
100 101 102 |
# File 'lib/rmtools/enumerable/range.rb', line 100 def -@ XRange(-Inf..prev_int(first), (exclude_end? ? last.ceil : next_int(last))..Inf) end |
#<<(i) ⇒ Object
Move range as interval left
230 231 232 |
# File 'lib/rmtools/enumerable/range.rb', line 230 def <<(i) first - i .. included_end - i end |
#<=>(range) ⇒ Object
176 177 178 |
# File 'lib/rmtools/enumerable/range.rb', line 176 def <=>(range) (first <=> range.first).b || included_end <=> range.included_end end |
#>>(i) ⇒ Object
Move range as interval right
225 226 227 |
# File 'lib/rmtools/enumerable/range.rb', line 225 def >>(i) first + i .. included_end + i end |
#^(range) ⇒ Object
Diff
171 172 173 174 |
# File 'lib/rmtools/enumerable/range.rb', line 171 def ^(range) common = self & range self - common | range - common end |
#b ⇒ Object
79 80 81 |
# File 'lib/rmtools/enumerable/range.rb', line 79 def b size != 0 && self end |
#center ⇒ Object Also known as: avg
Average
219 220 221 |
# File 'lib/rmtools/enumerable/range.rb', line 219 def center (first + included_end)/2 end |
#empty? ⇒ Boolean
Include any integer?
75 76 77 |
# File 'lib/rmtools/enumerable/range.rb', line 75 def empty? size == 0 end |
#evens ⇒ Object
214 215 216 |
# File 'lib/rmtools/enumerable/range.rb', line 214 def evens select {|i| i%2 == 0} end |
#include?(number_or_range) ⇒ Boolean
#include? corresponds with Ruby’s default one, which considers a range as an interval (0..1).include? 1.0 1.in 0..1
> true
and (0…1.0).include? 1.0
> false
127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/rmtools/enumerable/range.rb', line 127 def include?(number_or_range) if Numeric === number_or_range or String === number_or_range include_number? number_or_range elsif XRange === number_or_range number_or_range.include? self elsif Range === number_or_range include_number? number_or_range.first and include_number? number_or_range.last else raise TypeError, "can not find #{number_or_range.class} in Range" end end |
#include_end ⇒ Object
End inclusion need to universalize ranges for use in XRange list. Considering the extension domain, one simply should not use “…” notation, but if such a range nevertheless appears as an argument, we reduce that to an operable one at the cost of a fractional accuracy #include_end should not be coupled with #size and #empty? which have their own “…” handling (0.9…1.3).include_end # => 0.9..1, BUT (0.3…0.5).include_end # => 0.3..0
51 52 53 |
# File 'lib/rmtools/enumerable/range.rb', line 51 def include_end exclude_end? ? first..prev_int(last) : self end |
#include_number? ⇒ Object
120 |
# File 'lib/rmtools/enumerable/range.rb', line 120 alias :include_number? :include? |
#included_end ⇒ Object
55 56 57 |
# File 'lib/rmtools/enumerable/range.rb', line 55 def included_end exclude_end? ? prev_int(last) : last end |
#integerize ⇒ Object
Simplify a range to in-domain equivalent with integer edges.
84 85 86 |
# File 'lib/rmtools/enumerable/range.rb', line 84 def integerize first.ceil..int_end end |
#integers ⇒ Object Also known as: to_is
Significant content of a range then.
89 90 91 |
# File 'lib/rmtools/enumerable/range.rb', line 89 def integers integerize.to_a end |
#mask_ip ⇒ Object
72 73 74 75 76 77 78 79 80 |
# File 'lib/rmtools/conversions/ip.rb', line 72 def mask_ip i = nil 31.downto(12) {|i| lm = last.mask_ip(i) break if first.mask_ip(i) == lm and (last+1).mask_ip(i) != lm i = nil } i || 32 end |
#max(&fun) ⇒ Object
maximum of monotone function definition interval
200 201 202 203 204 205 206 207 208 |
# File 'lib/rmtools/enumerable/range.rb', line 200 def max(&fun) return last if yield last return unless yield first if yield(c = center) (c+1..last-1).max(&fun) || c else (first..c-1).max(&fun) end end |
#min(&fun) ⇒ Object
minimum of monotone function definition interval
189 190 191 192 193 194 195 196 197 |
# File 'lib/rmtools/enumerable/range.rb', line 189 def min(&fun) return first if yield first return unless yield last if yield(c = center) (first+1..c-1).min(&fun) || c else (c+1..last).min(&fun) end end |
#odds ⇒ Object
210 211 212 |
# File 'lib/rmtools/enumerable/range.rb', line 210 def odds select {|i| i%2 != 0} end |
#rand ⇒ Object
6 7 8 |
# File 'lib/rmtools/rand/range.rb', line 6 def rand self.begin + Kernel.rand(size) end |
#randseg ⇒ Object
10 11 12 |
# File 'lib/rmtools/rand/range.rb', line 10 def randseg (a = rand) > (b = rand) ? b..a : a..b end |
#size ⇒ Object
Represent a count of integers that range include and not real interval length (0..0).size
> 1 (equivalent list of one 0)
(0…0).size
> 0 (equivalent empty list)
(0.3..0.5).size
> 0 (there is no integer between 0.3 and 0.5)
(0.9…1.1).size
> 1 (equivalent list of one 1 which is between 0.9 and 1.1)
(2..1).size
> 0 (such a range just does’t make sense)
70 71 72 |
# File 'lib/rmtools/enumerable/range.rb', line 70 def size [int_end - first.ceil + 1, 0].max end |
#sum ⇒ Object
Sum of integers in a range
181 182 183 184 185 186 |
# File 'lib/rmtools/enumerable/range.rb', line 181 def sum last = included_end return (1..last).sum - (0..-first).sum if first < 0 return 0 if last <= first last*(last+1)/2 - (1..first-1).sum end |
#x?(range, pretend_not_exclude = false) ⇒ Boolean Also known as: intersects?
Does these ranges have at least one common point? (0..1).x? 1..2 (1…2).x? 0..1 (0..3).x? 1..2 (1..2).x? 0..3
> true
(0..1.4).x? 1.5..2 (0…1).x? 1..2 (2..3).x? 0..1
> false
149 150 151 152 153 |
# File 'lib/rmtools/enumerable/range.rb', line 149 def x?(range, pretend_not_exclude=false) return range.x? self if range.is XRange (range.last > first or ((!range.exclude_end? or pretend_not_exclude) and range.last == first)) and (range.first < last or ((!exclude_end? or pretend_not_exclude) and range.first == last)) end |
#|(range) ⇒ Object
Union (1..3) | (2..4)
> 1..4
(1…2) | (2..4)
> 1..4
(1..2) | (3..4)
> XRange(1..2, 3..4)
A result will be inadequate if any range is not integered and excludes end
164 165 166 167 168 |
# File 'lib/rmtools/enumerable/range.rb', line 164 def |(range) return range | self if range.is XRange return XRange.new self, range if !x?(range, true) [first, range.first].min..[included_end, range.included_end].max end |