Ruby 复杂范围操作帮助:确定给定计划和请求时间的可用时间范围

Ruby 复杂范围操作帮助:确定给定计划和请求时间的可用时间范围,ruby,data-structures,Ruby,Data Structures,因此,我试图建立一个预订应用程序,遇到了一些问题 基本上,我为客户安排了一系列约会: appointments = [ Mon, 29 Dec 2014 11:00:00 PST -08:00..Mon, 29 Dec 2014 12:30:00 PST -08:00, Mon, 29 Dec 2014 09:00:00 PST -08:00..Mon, 29 Dec 2014 10:30:00 PST -08:00, Mon, 29 Dec 2014 14:00:00

因此,我试图建立一个预订应用程序,遇到了一些问题

基本上,我为客户安排了一系列约会:

appointments = [
    Mon, 29 Dec 2014 11:00:00 PST -08:00..Mon, 29 Dec 2014 12:30:00 PST -08:00,
    Mon, 29 Dec 2014 09:00:00 PST -08:00..Mon, 29 Dec 2014 10:30:00 PST -08:00,
    Mon, 29 Dec 2014 14:00:00 PST -08:00..Mon, 29 Dec 2014 15:30:00 PST -08:00
]
然后我这次预定:

Mon, 29 Dec 2014 14:00:00 PST -08:00
它寻找一项需要一小时30分钟的服务,所以我想预订的时间范围是:

requested_time_range = Mon, 29 Dec 2014 14:00:00 PST -08:00..Mon, 29 Dec 2014 15:30:00 PST -08:00
当天的可用时间为:

full_time_range = Mon, 29 Dec 2014 07:30:00 PST -08:00..Mon, 29 Dec 2014 16:00:00 PST -08:00
使用range_操作符gem(),我能够做到这一点:

a1 = full_time_range - appointments.first
这将导致(范围操作
-
导致范围数组):

因此,循环遍历所有约会,并从完整的时间范围中扣除它们,然后格式化数组,使我们有一个平面数组,我提出:

available_times = [
    Mon, 29 Dec 2014 07:30:00 PST -08:00..Mon, 29 Dec 2014 10:59:59 PST -08:00,
    Mon, 29 Dec 2014 12:30:01 PST -08:00..Mon, 29 Dec 2014 15:00:00 PST -08:00,
    Mon, 29 Dec 2014 07:30:00 PST -08:00..Mon, 29 Dec 2014 08:59:59 PST -08:00,
    Mon, 29 Dec 2014 10:30:01 PST -08:00..Mon, 29 Dec 2014 15:00:00 PST -08:00,
    Mon, 29 Dec 2014 07:30:00 PST -08:00..Mon, 29 Dec 2014 13:59:59 PST -08:00,
    Mon, 29 Dec 2014 07:30:00 PST -08:00..Mon, 29 Dec 2014 08:59:59 PST -08:00,
    Mon, 29 Dec 2014 10:30:01 PST -08:00..Mon, 29 Dec 2014 15:00:00 PST -08:00,
    Mon, 29 Dec 2014 07:30:00 PST -08:00..Mon, 29 Dec 2014 13:59:59 PST -08:00 
]
现在我不太清楚的是,如何找到
请求的时间范围
是否包含在
可用时间
中。大多数情况下,它并不准确,因为请求的时间范围有时在可用时间数组的一个元素内,有时不在其中


在我的情况下,是否有一种准确的方法来确定
请求的时间范围
是否可用?(我想我必须对可用的时间做些什么,但我不知道您需要更改您的请求时间范围,使其
最大值小于当前值1秒(或更多)

booking_time = some_time # "Mon, 29 Dec 2014 14:00:00 PST -08:00" in your case
# 5399.seconds equals (1.5.hours - 1.second )
request_time_range = booking_time..(booking_time + 5399.seconds)
那么下面的应该会起作用:

available_times.any? do |time_range|
  (time_range.min <= requested_time_range.min) &&
  (time_range.max >= requested_time_range.max)
end
available_times.any?do|time_range|
(time\u range.min=请求的时间\u range.max)
结束

我以自己的方式做这件事,玩得很开心……这件事可能适合你,也可能不适合你,速度还有提升的空间,但以下是我的想法。你可以随心所欲地将它与你的情况结合起来

编辑:我还没有对所有场景进行测试


范围\u比较.rb

####
## Use case: Are you available between Nov 19th and 30th?
## No, I'm only available between Dec 1st and 2nd
## 
## requested_dates = DateTime.parse("Nov 19, 2014")..DateTime.parse("Nov 30, 2014")
## available_dates = DateTime.parse("Dec 1, 2014")..DateTime.parse("Dec 2, 2014")
## p 'Dates intersect on: '
## p requested_dates.first_coincide_with(available_dates)
####

class Range
  def first_coincide_with(compared_range)
    # Barf if it's anything other than a Range
    raise(ArgumentError, 'Only Ranges are permitted!') unless compared_range.kind_of?(Range)
    # Find the closest starting point for searching
    min = [self.min, compared_range.min].max
    # Find the end time
    max = [self.max, compared_range.max].min
    # Quickly exit if they are completely out of bounds to one another
    return if min > max

    # Now start searching for first available unit
    # Hopefully they know to use this in a strictly Integer Range... :)
    pos = min
    until pos > max
      return pos if pos >= min
      pos += 1
    end
    nil
  end
end

问题是约会不是一个包含范围。应该排除结束时间,因此在构建范围时使用
而不是

假设您有一个
9到10:30
10:30到12
。在包含范围的情况下,您会得到一个如下所示的时间表:

|------|
       |------|
而不是排除最后一个值:

|------|------
在没有重叠的情况下,检查范围数组是否不包含新范围,确保没有范围包含新范围的开始或结束

def include?(ranges, range)
  ranges.any?{ |r| r.cover?(range.begin) || r.cover?(range.end) }
end

def valid?(appointments, appointment)
  !include?(appointments, appointment)
end
请注意和之间的区别。是否要
封面?

编辑:要查找可用时间,请对范围进行排序并获取非零间隙

def available_ranges(ranges)
  pairs = ranges.sort_by(&:begin).each_cons(2)
  new_ranges = pairs.map do |r1, r2|
    r1.end...r2.begin
  end
  new_ranges.reject{ |r| r.begin == r.end }
end
def available_ranges(ranges)
  pairs = ranges.sort_by(&:begin).each_cons(2)
  new_ranges = pairs.map do |r1, r2|
    r1.end...r2.begin
  end
  new_ranges.reject{ |r| r.begin == r.end }
end