Module: Philiprehberger::Interval

Defined in:
lib/philiprehberger/interval.rb,
lib/philiprehberger/interval/range.rb,
lib/philiprehberger/interval/version.rb

Defined Under Namespace

Classes: Error, Range

Constant Summary collapse

VALID_TYPES =
%i[closed open left_open right_open].freeze
VERSION =
'0.3.0'

Class Method Summary collapse

Class Method Details

.gaps(intervals) ⇒ Array<Range>

Find gaps between a collection of intervals.

Parameters:

  • intervals (Array<Range>)

    the intervals to analyze

Returns:

  • (Array<Range>)

    gaps between the merged intervals



60
61
62
63
64
65
66
67
68
69
# File 'lib/philiprehberger/interval.rb', line 60

def self.gaps(intervals)
  merged = merge(intervals)
  return [] if merged.length < 2

  result = []
  merged.each_cons(2) do |a, b|
    result << Range.new(a.finish, b.start) if a.finish < b.start
  end
  result
end

.intersection(intervals) ⇒ Range?

Compute the common overlap across a collection of intervals.

Parameters:

  • intervals (Array<Range>)

    the intervals to intersect

Returns:

  • (Range, nil)

    the common intersection, or nil if any pair is disjoint



46
47
48
49
50
51
52
53
54
# File 'lib/philiprehberger/interval.rb', line 46

def self.intersection(intervals)
  return nil if intervals.empty?

  intervals[1..].reduce(intervals.first) do |acc, current|
    return nil if acc.nil?

    acc.intersect(current)
  end
end

.merge(intervals) ⇒ Array<Range>

Merge a collection of overlapping or adjacent intervals into non-overlapping intervals.

Parameters:

  • intervals (Array<Range>)

    the intervals to merge

Returns:

  • (Array<Range>)

    merged, sorted, non-overlapping intervals



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/philiprehberger/interval.rb', line 23

def self.merge(intervals)
  return [] if intervals.empty?

  sorted = intervals.sort
  merged = [sorted.first]

  sorted[1..].each do |current|
    last = merged.last
    combined = last.union(current)
    if combined
      merged[-1] = combined
    else
      merged << current
    end
  end

  merged
end

.new(start, finish, type: :closed) ⇒ Range

Create a new interval.

Parameters:

  • start (Comparable)

    the start value

  • finish (Comparable)

    the end value

Returns:

  • (Range)

    a new interval



15
16
17
# File 'lib/philiprehberger/interval.rb', line 15

def self.new(start, finish, type: :closed)
  Range.new(start, finish, type: type)
end