Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 如何从其他间隔中构建间隔数组_Ruby_Algorithm_Data Structures - Fatal编程技术网

Ruby 如何从其他间隔中构建间隔数组

Ruby 如何从其他间隔中构建间隔数组,ruby,algorithm,data-structures,Ruby,Algorithm,Data Structures,给定以下间隔数组: today = Time.current.beginning_of_day tomorrow = Time.current.tomorrow.beginning_of_day availabilities = { monday: [ { start_time: today + 6.hours, end_of_time: today + 12.hours }, { start_time: today + 8.hours, end_o

给定以下间隔数组:

today = Time.current.beginning_of_day
tomorrow = Time.current.tomorrow.beginning_of_day

availabilities = {
  monday: [
    { start_time: today + 6.hours,
      end_of_time: today + 12.hours },
    { start_time: today + 8.hours,
      end_of_time: today + 18.hours }
  ],
  tuesday: [
    { start_time: tomorrow + 10.hours,
      end_time: tomorrow + 16.hours },
    { start_time: tomorrow + 18.hours,
      end_time: tomorrow + 23.hours }
  ]
}
如何使用间隔构建
可用性的数组,例如在
星期一
星期二
的情况下,哈希:

# monday
{ start_time: 'Today at 06:00',
  end_time: 'Today at 18:00' }
# tuesday
[ { start_time: 'Tomorrow at 10:00',
    end_time: 'Tomorrow at 16:00' },
  { start_time: 'Tomorrow at 18:00',
    end_time: 'Tomorrow at 23:00' } ]
我想要实现的是获得给定日期的可用性间隔,而不管哪个实体将提供该可用性

请提前感谢,对于使用哪种算法的任何帮助或指导都将不胜感激

  • 按开始时间对间隔进行排序
  • 从第一个间隔开始,检查它是否与下一个间隔重叠
  • 如果是,则合并它们并重复该过程
  • 如果否,继续下一个间隔
  • 证明其有效的证据:

    如果对间隔A、B和C进行排序,并且A和C重叠,这也意味着B肯定与A重叠

    这里有一种在Ruby中实现的方法

    def overlap?(r1, r2)
      !(r1.end <= r2.begin || r1.begin >= r2.end)
    end
    
    def merge_intervals(r1, r2)
      [r1.begin, r2.begin].min..[r1.end, r2.end].max
    end
    
    def flatten_intervals(intervals)
      first, *rest = intervals.sort_by(&:begin)
      rest.each_with_object([first]) { |r,stack| stack <<
        (overlap?(stack.last, r) ? merge_intervals(stack.pop, r) : r) }
    end
    
    intervals = [0..2, 5..8, 4..9, 11..13, 15..17, 19..21, 17..19, 16..20]
    flatten_intervals(intervals)
      #=> [0..2, 4..9, 11..13, 15..21]
    
    def重叠?(r1、r2)
    !(r1.end=r2.end)
    结束
    def合并_间隔(r1、r2)
    [r1.begin,r2.begin].min..[r1.end,r2.end].max
    结束
    def展平间隔(间隔)
    首先,*rest=interval.sort_by(&:begin)
    rest.each_with_object([first]){| r,stack | stack[0..2,4..9,11..13,15..21]
    
    这里有一种将时间间隔数组转换为非重叠时间间隔数组的简单方法。我假设粒度为1小时(但将其更改为分钟或秒很简单)。为方便起见,我还将时间间隔表示为范围,而不是问题中指定的哈希(尽管将范围转换为散列很容易)

    假设

    time_intervals = [0..2, 5..8, 4..9, 11..13, 15..17, 19..21, 17..19, 16..20]
    
    我们可以按如下方式查看这些时间间隔:

    00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
    xx xx xx       xx xx xx xx       xx xx xx    xx xx xx    xx xx xx
                xx xx xx xx xx xx                      xx xx xx 
                                                    xx xx xx xx xx
    
    e.entries
      #=> [[0, 1, 2], [4, 5, 6, 7, 8, 9], [11, 12, 13], [15, 16, 17, 18, 19, 20, 21]]
    
    我们希望将这些结合起来:

    00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
    xx xx xx    xx xx xx xx xx xx    xx xx xx    xx xx xx xx xx xx xx xx 
    
    一个简单的方法如下

    h = 24.times.with_object({}) { |i,h| h[i] = :uncovered } 
    time_intervals.each { |range|
      (range.begin..range.end).each { |i| h[i] = :covered } }
    h.delete_if { |_,v| v == :uncovered }.
      keys.
      slice_when { |k1, k2| k2 - k1 > 1 }.
      map { |a| a.first..a.last }
      #=> [0..2, 4..9, 11..13, 15..21]
    
    h = 24.times.with_object({}) { |i,h| h[i] = :uncovered } 
      #=> {0=>:uncovered, 1=>:uncovered, 2=>:uncovered,..., 23=>:uncovered} 
    time_intervals.each { |range|
      (range.begin..range.end).each { |i| h[i] = :covered } }
    h #=> { all k=>:covered except k=>:uncovered for k = 3, 10, 14, 22 and 23 } 
    g = h.delete_if { |_,v| v == :uncovered }
      #=> { all k=>:covered, k = 1,2, 4,5,6,7,8,9, 11,12,13, 15,16,17,18,19,20,21v]
    k = g.keys
      #=> [0, 1, 2, 4, 5, 6, 7, 8, 9, 11, 12, 13, 15, 16, 17, 18, 19, 20, 21] 
    e = k.slice_when { |k1, k2| k2 - k1 > 1 }
      #=> #<Enumerator: #<Enumerator::Generator:0x007fee0a05c7b0>:each> 
    
    步骤如下

    h = 24.times.with_object({}) { |i,h| h[i] = :uncovered } 
    time_intervals.each { |range|
      (range.begin..range.end).each { |i| h[i] = :covered } }
    h.delete_if { |_,v| v == :uncovered }.
      keys.
      slice_when { |k1, k2| k2 - k1 > 1 }.
      map { |a| a.first..a.last }
      #=> [0..2, 4..9, 11..13, 15..21]
    
    h = 24.times.with_object({}) { |i,h| h[i] = :uncovered } 
      #=> {0=>:uncovered, 1=>:uncovered, 2=>:uncovered,..., 23=>:uncovered} 
    time_intervals.each { |range|
      (range.begin..range.end).each { |i| h[i] = :covered } }
    h #=> { all k=>:covered except k=>:uncovered for k = 3, 10, 14, 22 and 23 } 
    g = h.delete_if { |_,v| v == :uncovered }
      #=> { all k=>:covered, k = 1,2, 4,5,6,7,8,9, 11,12,13, 15,16,17,18,19,20,21v]
    k = g.keys
      #=> [0, 1, 2, 4, 5, 6, 7, 8, 9, 11, 12, 13, 15, 16, 17, 18, 19, 20, 21] 
    e = k.slice_when { |k1, k2| k2 - k1 > 1 }
      #=> #<Enumerator: #<Enumerator::Generator:0x007fee0a05c7b0>:each> 
    
    请参阅。也可以使用

    最后一步是将数组转换为范围

    e.map { |a| a.first..a.last }
      #=> [0..2, 4..9, 11..13, 15..21]
    

    合并重叠间隔的算法:

    1. Sort the intervals on start time
    2. Assign left and right of first interval (0)
    3. Iterate over the intervals from 1 to size-1
        if (current interval start lies in prev. interval)
            update right to max(prev. right, current. right) 
        else
            [left, right] is non-overlapping interval => push it to answer array
            reassign left and right to current interval
    4. push last [left, right] to answer array
    
    解决方案:

    # hash of overlapping intervals
    availabilities = {
      monday: [
        { start_time: 6,
          end_time: 12 },
        { start_time: 8,
          end_time: 18 }
      ],
      tuesday: [
        { start_time: 10,
          end_time: 16 },
        { start_time: 18,
          end_time: 23 }
      ]
    }
    
    # function for converting hash to intervals, process, and then convert back to hash
    def solve(list)
        return_hash = {}
        list.each do |key, arr|
            intervals = []
            arr.each { |hash| intervals << [hash[:start_time], hash[:end_time]] }
            non_overlapping_intervals = merge_interval(intervals)
            temp = []
            non_overlapping_intervals.each { |interval| temp << {start_time: interval[0], end_time: interval[1]} }
            return_hash[key] = temp
        end
        return_hash
    end
    
    # algorithm to merge intervals and return non-overlapping intervals
    def merge_interval(v)
        intervals = []
        v.sort()
        size = v.size()
        l, r = v[0][0], v[0][1]
        (1...size).each do |i|
            if v[i][0] <= r
                r = [r,v[i][1]].max;
            else
                intervals << [l, r]
                l, r = v[i][0], v[i][1]
            end         
        end
        intervals << [l, r]
        return intervals
    end
    
    # solve call for availabilities hash
    p solve(availabilities)
    

    使用稍微不同的格式(一个范围,而不是具有不一致键的哈希),此问题变得更容易:

    today = 0
    tomorrow = 24
    
    availabilities = {
      monday: [
        { start_time: today + 6,
          end_time: today + 12 },
        { start_time: today + 8,
          end_time: today + 18 }
      ],
      tuesday: [
        { start_time: tomorrow + 10,
          end_time: tomorrow + 16 },
        { start_time: tomorrow + 18,
          end_time: tomorrow + 23 }
      ]
    }
    
    availabilities = availabilities.map do |day, avails|
      [ day,
        avails.map do |avail|
          (avail[:start_time]..avail[:end_time])
        end
      ]
    end.to_h
    # {:monday=>[6..12, 8..18], :tuesday=>[34..40, 42..47]}
    

    然后,您可以使用来对范围进行求和。

    时间间隔=[0..2,3..4]
    将忽略2和3之间的暂停。@Eric,这就是我的意图,因为我将
    0..2
    3..4
    视为小时的集合(
    [0,1,2]
    [3,4]
    )而不是连续区间的表示。然而,我并不特别喜欢这个解决方案。恐怕它没有回答这个问题。优秀的算法:高效和容易理解。代码本来是好的,但是我认为省略。Ekkima,请随意编辑或删除我添加的代码。它是一个很好的A。回答:我想一些代码可以把它完善。