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
228 229 230 |
# File 'lib/rmtools/enumerable/range.rb', line 228 def <<(i) first - i .. included_end - i end |
#<=>(range) ⇒ Object
174 175 176 |
# File 'lib/rmtools/enumerable/range.rb', line 174 def <=>(range) (first <=> range.first).b || included_end <=> range.included_end end |
#>>(i) ⇒ Object
Move range as interval right
223 224 225 |
# File 'lib/rmtools/enumerable/range.rb', line 223 def >>(i) first + i .. included_end + i end |
#^(range) ⇒ Object
Diff
169 170 171 172 |
# File 'lib/rmtools/enumerable/range.rb', line 169 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
217 218 219 |
# File 'lib/rmtools/enumerable/range.rb', line 217 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
212 213 214 |
# File 'lib/rmtools/enumerable/range.rb', line 212 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 |
# File 'lib/rmtools/enumerable/range.rb', line 127 def include?(number_or_range) if Numeric === number_or_range include_number? number_or_range elsif XRange === number_or_range number_or_range.include? self else include_number? number_or_range.first and include_number? number_or_range.last 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
198 199 200 201 202 203 204 205 206 |
# File 'lib/rmtools/enumerable/range.rb', line 198 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
187 188 189 190 191 192 193 194 195 |
# File 'lib/rmtools/enumerable/range.rb', line 187 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
208 209 210 |
# File 'lib/rmtools/enumerable/range.rb', line 208 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
179 180 181 182 183 184 |
# File 'lib/rmtools/enumerable/range.rb', line 179 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
147 148 149 150 151 |
# File 'lib/rmtools/enumerable/range.rb', line 147 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
162 163 164 165 166 |
# File 'lib/rmtools/enumerable/range.rb', line 162 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 |