Class: Range
- Defined in:
- lib/rmtools/enumerable/range.rb,
lib/rmtools/rand/range.rb,
lib/rmtools/conversions/ip.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
232 233 234 |
# File 'lib/rmtools/enumerable/range.rb', line 232 def <<(i) first - i .. included_end - i end |
#<=>(range) ⇒ Object
178 179 180 |
# File 'lib/rmtools/enumerable/range.rb', line 178 def <=>(range) (first <=> range.first).b || included_end <=> range.included_end end |
#>>(i) ⇒ Object
Move range as interval right
227 228 229 |
# File 'lib/rmtools/enumerable/range.rb', line 227 def >>(i) first + i .. included_end + i end |
#^(range) ⇒ Object
Diff
173 174 175 176 |
# File 'lib/rmtools/enumerable/range.rb', line 173 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
221 222 223 |
# File 'lib/rmtools/enumerable/range.rb', line 221 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
216 217 218 |
# File 'lib/rmtools/enumerable/range.rb', line 216 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 138 139 |
# 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" # activerecord 4.0 tells it must not raise false 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
202 203 204 205 206 207 208 209 210 |
# File 'lib/rmtools/enumerable/range.rb', line 202 def max(&fun) return last if !fun or 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
191 192 193 194 195 196 197 198 199 |
# File 'lib/rmtools/enumerable/range.rb', line 191 def min(&fun) return first if !fun or 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
212 213 214 |
# File 'lib/rmtools/enumerable/range.rb', line 212 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
183 184 185 186 187 188 |
# File 'lib/rmtools/enumerable/range.rb', line 183 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
151 152 153 154 155 |
# File 'lib/rmtools/enumerable/range.rb', line 151 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
166 167 168 169 170 |
# File 'lib/rmtools/enumerable/range.rb', line 166 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 |