lib/multi_range.rb in multi_range-0.0.3 vs lib/multi_range.rb in multi_range-0.0.4
- old
+ new
@@ -1,103 +1,125 @@
-require 'multi_range/version'
-require 'roulette-wheel-selection'
-
-if not Range.method_defined?(:size)
- warn "Please backports Range#size method to use multi_range gem.\n" \
- "You can use backports gem and add the following lines to your program:\n" \
- "require 'backports/1.9.2/float/infinity'\n" \
- "require 'backports/2.0.0/range/size'"
-end
-
-if not Enumerable.method_defined?(:to_h)
- warn "Please backports Enumerable#to_h method to use multi_range gem.\n" \
- "You can use backports gem and add the following lines to your program:\n" \
- "require 'backports/2.1.0/enumerable/to_h'"
-end
-
-class MultiRange
- INDEX_WITH_DEFAULT = Object.new
-
- attr_reader :ranges
-
- def initialize(ranges) # range 要由小到大排序,且各 range 不能重疊
- @ranges = ranges.map{|s| s.is_a?(Integer) ? s..s : s }.freeze
- end
-
- def -(other)
- new_ranges = @ranges.dup
-
- return MultiRange.new(new_ranges) if new_ranges.empty?
- return MultiRange.new(new_ranges) if other.min > @ranges.last.max # 大於最大值
- return MultiRange.new(new_ranges) if other.max < @ranges.first.min # 小於最小值
-
- changed_size = 0
- @ranges.each_with_index do |range, idx|
- next if other.min > range.max # 大於這個 range
- break if other.max < range.min # 小於這個 range
-
- sub_range1 = range.min...other.min
- sub_range2 = (other.max + 1)..range.max
-
- sub_ranges = []
- sub_ranges << sub_range1 if sub_range1.any?
- sub_ranges << sub_range2 if sub_range2.any?
-
- new_ranges[idx + changed_size, 1] = sub_ranges
- changed_size += sub_ranges.size - 1
- break if other.max <= range.max # 沒有超過一個 range 的範圍
- end
-
- return MultiRange.new(new_ranges)
- end
-
- def sample
- range = RouletteWheelSelection.sample(@ranges.map{|s| [s, s.size] }.to_h)
- return nil if range == nil
- return rand(range.max - range.min) + range.min
- end
-
- def size
- @ranges.inject(0){|sum, v| sum + v.size }
- end
-
- def any?
- @ranges.any?
- end
-
- 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
-
- def each
- return to_enum(:each){ size } if !block_given?
-
- ranges.each do |range|
- range.each{|s| yield(s) }
- end
- end
-
- def map
- return to_enum(:map){ size } if !block_given?
- return each.map{|s| yield(s) }
- end
-
- def to_a
- each.to_a
- end
-
- def min
- range = @ranges.first
- return range.min if range
- end
-
- def max
- range = @ranges.last
- return range.max if range
- end
-end
+require 'multi_range/version'
+require 'roulette-wheel-selection'
+
+if not Range.method_defined?(:size)
+ warn "Please backports Range#size method to use multi_range gem.\n" \
+ "You can use backports gem and add the following lines to your program:\n" \
+ "require 'backports/1.9.2/float/infinity'\n" \
+ "require 'backports/2.0.0/range/size'"
+end
+
+if not Enumerable.method_defined?(:to_h)
+ warn "Please backports Enumerable#to_h method to use multi_range gem.\n" \
+ "You can use backports gem and add the following lines to your program:\n" \
+ "require 'backports/2.1.0/enumerable/to_h'"
+end
+
+class MultiRange
+ INDEX_WITH_DEFAULT = Object.new
+
+ attr_reader :ranges
+
+ def initialize(ranges) # range 要由小到大排序,且各 range 不能重疊
+ @ranges = ranges.map{|s| s.is_a?(Integer) ? s..s : s }.freeze
+ end
+
+ def flatten
+ return if @ranges.size == 0
+
+ new_ranges = []
+ current_range = nil
+
+ @ranges.each do |range|
+ next current_range = range if current_range == nil
+ next if range.max <= current_range.max
+
+ if current_range.max + 1 < range.min
+ new_ranges << current_range
+ current_range = range
+ else
+ current_range = current_range.min..range.max
+ end
+ end
+
+ new_ranges << current_range
+ return MultiRange.new(new_ranges)
+ end
+
+ def -(other)
+ new_ranges = @ranges.dup
+
+ return MultiRange.new(new_ranges) if new_ranges.empty?
+ return MultiRange.new(new_ranges) if other.min > @ranges.last.max # 大於最大值
+ return MultiRange.new(new_ranges) if other.max < @ranges.first.min # 小於最小值
+
+ changed_size = 0
+ @ranges.each_with_index do |range, idx|
+ next if other.min > range.max # 大於這個 range
+ break if other.max < range.min # 小於這個 range
+
+ sub_range1 = range.min...other.min
+ sub_range2 = (other.max + 1)..range.max
+
+ sub_ranges = []
+ sub_ranges << sub_range1 if sub_range1.any?
+ sub_ranges << sub_range2 if sub_range2.any?
+
+ new_ranges[idx + changed_size, 1] = sub_ranges
+ changed_size += sub_ranges.size - 1
+ break if other.max <= range.max # 沒有超過一個 range 的範圍
+ end
+
+ return MultiRange.new(new_ranges)
+ end
+
+ def sample
+ range = RouletteWheelSelection.sample(@ranges.map{|s| [s, s.size] }.to_h)
+ return nil if range == nil
+ return rand(range.max - range.min) + range.min
+ end
+
+ def size
+ @ranges.inject(0){|sum, v| sum + v.size }
+ end
+
+ def any?
+ @ranges.any?
+ end
+
+ 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
+
+ def each
+ return to_enum(:each){ size } if !block_given?
+
+ ranges.each do |range|
+ range.each{|s| yield(s) }
+ end
+ end
+
+ def map
+ return to_enum(:map){ size } if !block_given?
+ return each.map{|s| yield(s) }
+ end
+
+ def to_a
+ each.to_a
+ end
+
+ def min
+ range = @ranges.first
+ return range.min if range
+ end
+
+ def max
+ range = @ranges.last
+ return range.max if range
+ end
+end