Class: MultiRange
- Inherits:
-
Object
- Object
- MultiRange
- Defined in:
- lib/multi_range.rb,
lib/multi_range/version.rb
Constant Summary collapse
- INDEX_WITH_DEFAULT =
Object.new
- VERSION =
'2.2.3'
Instance Attribute Summary collapse
-
#ranges ⇒ Object
readonly
Returns the value of attribute ranges.
Instance Method Summary collapse
- #&(other) ⇒ Object (also: #intersection)
- #-(other) ⇒ Object (also: #difference)
- #any? ⇒ Boolean
- #contain_overlaps? ⇒ Boolean
- #each ⇒ Object
- #index_with(default = INDEX_WITH_DEFAULT) ⇒ Object
-
#initialize(ranges) ⇒ MultiRange
constructor
A new instance of MultiRange.
- #is_float? ⇒ Boolean
- #map ⇒ Object
- #max ⇒ Object
- #merge_overlaps(merge_same_value = true) ⇒ Object
- #min ⇒ Object
- #overlaps?(other) ⇒ Boolean
- #sample ⇒ Object
- #size ⇒ Object
- #to_a ⇒ Object
- #|(other) ⇒ Object (also: #union)
Constructor Details
#initialize(ranges) ⇒ MultiRange
Returns a new instance of MultiRange.
26 27 28 29 30 31 32 33 34 35 |
# File 'lib/multi_range.rb', line 26 def initialize(ranges) if ranges.is_a? MultiRange @ranges = ranges.ranges @is_float = ranges.is_float? else ranges = [ranges] if !ranges.is_a?(Array) @ranges = ranges.map{|s| s.is_a?(Numeric) ? s..s : s }.sort_by{|s| s.begin || -Float::INFINITY }.freeze @is_float = @ranges.any?{|range| range.begin.is_a?(Float) || range.end.is_a?(Float) } end end |
Instance Attribute Details
#ranges ⇒ Object (readonly)
Returns the value of attribute ranges.
24 25 26 |
# File 'lib/multi_range.rb', line 24 def ranges @ranges end |
Instance Method Details
#&(other) ⇒ Object Also known as: intersection
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/multi_range.rb', line 66 def &(other) other_ranges = MultiRange.new(other).merge_overlaps.ranges tree = IntervalTree::Tree.new(other_ranges){|l, r| r ? (l...(r + 1)) : l...nil } intersected_ranges = merge_overlaps.ranges.flat_map do |range| matching_ranges_converted_to_exclusive = tree.search(range) || [] # The interval tree converts interval endings to exclusive, so we need to restore the original matching_ranges = matching_ranges_converted_to_exclusive.map do |matching_range_converted_to_exclusive| other_ranges.find do |other_range| # Having merged overlaps in each multi_range, there's no need to check the endings, # since there will only be one range with each beginning other_range.begin == matching_range_converted_to_exclusive.begin end end matching_ranges.map do |matching_range| intersect_two_ranges(range, matching_range) end end MultiRange.new(intersected_ranges) end |
#-(other) ⇒ Object Also known as: difference
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/multi_range.rb', line 91 def -(other) return difference_with_other_multi_range(other) if other.is_a?(MultiRange) new_ranges = @ranges.dup return MultiRange.new(new_ranges) if not overlaps_with_range?(other) changed_size = 0 @ranges.each_with_index do |range, idx| # when this range is smaller than and not overlaps with `other` # range other # |---------| |---------| next if other.begin && range.end && other.begin > range.end # when this range is larger than and not overlaps with `other` # other range # |---------| |---------| break if other.end && range.begin && other.end < range.begin sub_ranges = possible_sub_ranges_of(range, other) new_ranges[idx + changed_size, 1] = sub_ranges changed_size += sub_ranges.size - 1 # when the maximum value of this range is larger than that of `other` # range # -------------| # other # ---------| break if range.end == nil break if other.end && other.end <= range.end end return MultiRange.new(new_ranges) end |
#any? ⇒ Boolean
149 150 151 |
# File 'lib/multi_range.rb', line 149 def any? @ranges.any? end |
#contain_overlaps? ⇒ Boolean
190 191 192 |
# File 'lib/multi_range.rb', line 190 def contain_overlaps? merge_overlaps(false).ranges != ranges end |
#each ⇒ Object
163 164 165 166 167 168 169 |
# File 'lib/multi_range.rb', line 163 def each return to_enum(:each){ size } if !block_given? ranges.each do |range| range.each{|s| yield(s) } end end |
#index_with(default = INDEX_WITH_DEFAULT) ⇒ Object
153 154 155 156 157 158 159 160 161 |
# File 'lib/multi_range.rb', line 153 def index_with(default = INDEX_WITH_DEFAULT) if block_given? fail ArgumentError, 'wrong number of arguments (given 1, expected 0)' if default != INDEX_WITH_DEFAULT return map{|s| [s, yield(s)] }.to_h end return to_enum(:index_with){ size } if default == INDEX_WITH_DEFAULT return map{|s| [s, default] }.to_h end |
#is_float? ⇒ Boolean
37 38 39 |
# File 'lib/multi_range.rb', line 37 def is_float? @is_float end |
#map ⇒ Object
171 172 173 174 |
# File 'lib/multi_range.rb', line 171 def map return to_enum(:map){ size } if !block_given? return each.map{|s| yield(s) } end |
#max ⇒ Object
185 186 187 188 |
# File 'lib/multi_range.rb', line 185 def max range = @ranges.last return range.max if range end |
#merge_overlaps(merge_same_value = true) ⇒ Object
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/multi_range.rb', line 41 def merge_overlaps(merge_same_value = true) return MultiRange.new([]) if @ranges.size == 0 new_ranges = [] current_range = nil @ranges.each do |range| next current_range = range if current_range == nil next if current_range.end == nil next if range.end && range.end <= current_range.end if can_combine?(current_range, range, merge_same_value) end_val = range.end end_val = Float::INFINITY if end_val == nil && current_range.begin == nil current_range = range.exclude_end? ? current_range.begin...end_val : current_range.begin..end_val else new_ranges << current_range current_range = range end end new_ranges << current_range return MultiRange.new(new_ranges) end |
#min ⇒ Object
180 181 182 183 |
# File 'lib/multi_range.rb', line 180 def min range = @ranges.first return range.min if range end |
#overlaps?(other) ⇒ Boolean
134 135 136 137 |
# File 'lib/multi_range.rb', line 134 def overlaps?(other) multi_range = merge_overlaps return multi_range.ranges != (multi_range - other).ranges end |
#sample ⇒ Object
139 140 141 142 143 |
# File 'lib/multi_range.rb', line 139 def sample range = RouletteWheelSelection.sample(@ranges.map{|s| [s, s.size] }.to_h) return nil if range == nil return rand(range) end |
#size ⇒ Object
145 146 147 |
# File 'lib/multi_range.rb', line 145 def size @ranges.inject(0){|sum, v| sum + v.size } end |
#to_a ⇒ Object
176 177 178 |
# File 'lib/multi_range.rb', line 176 def to_a each.to_a end |
#|(other) ⇒ Object Also known as: union
127 128 129 130 |
# File 'lib/multi_range.rb', line 127 def |(other) other_ranges = other.is_a?(MultiRange) ? other.ranges : [other] return MultiRange.new(@ranges + other_ranges).merge_overlaps end |