Detecting overlapping ranges in Ruby

前端 未结 4 1229
孤街浪徒
孤街浪徒 2021-01-03 06:50

I have array of ranges :

[[39600..82800], [39600..70200],[70200..80480]]

I need to determine if there is overlapping or not.What is an easy

相关标签:
4条回答
  • 2021-01-03 07:22

    Consider this:

    class Range
      include Comparable
    
      def <=>(other)
        self.begin <=> other.begin
      end
    
      def self.overlap?(*ranges)
        edges = ranges.sort.flat_map { |range| [range.begin, range.end] }
        edges != edges.sort.uniq
      end
    end
    
    Range.overlap?(2..12, 6..36, 42..96) # => true
    

    Notes:

    1. This could take in any number of ranges.
    2. Have a look at the gist with some tests to play with the code.
    3. The code creates a flat array with the start and end of each range.
    4. This array will retain the order if they don't overlap. (Its easier to visualize with some examples than textually explaining why, try it).
    0 讨论(0)
  • 2021-01-03 07:22

    For sake of simplicity and readability I'll suggest this approach:

    def overlaps?(ranges)
      ranges.each_with_index do |range, index|
        (index..ranges.size).each do |i|
          nextRange = ranges[i] unless index == i
          if nextRange and  range.to_a & nextRange.to_a 
            puts "#{range} overlaps with #{nextRange}"
          end
        end
      end
    end
    
    
    r = [(39600..82800), (39600..70200),(70200..80480)]
    overlaps?(r)
    

    and the output:

    ruby ranges.rb 
    39600..82800 overlaps with 39600..70200
    39600..82800 overlaps with 70200..80480
    39600..70200 overlaps with 70200..80480
    
    0 讨论(0)
  • 2021-01-03 07:40

    This is a very interesting puzzle, especially if you care about performances.

    If the ranges are just two, it's a fairly simple algorithm, which is also covered in ActiveSupport overlaps? extension.

    def ranges_overlap?(r1, r2)
      r1.cover?(r2.first) || r2.cover?(r1.first)
    end
    

    If you want to compare multiple ranges, it's a fairly interesting algorithm exercise.

    You could loop over all the ranges, but you will need to compare each range with all the other possibilities, but this is an algorithm with exponential cost.

    A more efficient solution is to order the ranges and execute a binary search, or to use data structures (such as trees) to make possible to compute the overlapping.

    This problem is also explained in the Interval tree page. Computing an overlap essentially consists of finding the intersection of the trees.

    0 讨论(0)
  • 2021-01-03 07:49

    Is this not a way to do it?

    def any_overlapping_ranges(array_of_ranges)
       array_of_ranges.sort_by(&:first).each_cons(2).any?{|x,y|x.last>y.first}
    end
    
    p any_overlapping_ranges([50..100, 1..51,200..220]) #=> True
    
    0 讨论(0)
提交回复
热议问题