如何找到,如果范围包含在范围内的阵列?(How to find if range is contai

2019-08-31 13:00发布

business_hours['monday'] = [800..1200, 1300..1700]
business_hours['tuesday'] = [900..1100, 1300..1700]

...

然后我有一大堆的活动占用一些时间间隔,例如

event = { start_at: somedatetime, end_at: somedatetime }

遍历从某个特定日期的事件某个日期,创建另一个数组

busy_hours['monday'] = [800..830, 1400..1415]

...

现在我的挑战

  • 创建包含business_hours减去busy_hours的available_hours阵列

available_hours = business_hours - busy_hours

  • 给予一定的持续时间说30分钟,发现其中时隙为available_hours可用。 在上面的例子中,这样的方法将返回

available_slots['monday'] = [830..900, 845..915, 900..930, and so on]

不它检查在指定的时间的时隙15分钟为增量available_hours。

谢谢您的帮助!

Answer 1:

我认为这是对位字段的工作。 不幸的是这种解决方案将依托神奇数字,转换助手和二进制逻辑的公平一点,所以它不会是漂亮。 但它会工作,是非常有效的。

这是我会处理这个问题:

雾化你的日子到合理的时间间隔。 我会按照你的榜样和治疗的时间每次15分钟块作为考虑的一个时间块(主要是因为它使例子简单)。 然后,代表每小时的可用性作为一个十六进制数字。

例:

  • 0xF = 0x1111 =>可用于整个小时。
  • 位于0xC =从0x1100 =>可用于小时的前半部分。

这些串24一起,共同代表了一天。 或更少,如果你可以肯定的是没有事件的范围之外发生。 该示例假设继续24小时。

从这一点上我长期分裂的十六进制数成文字的可读性假设当天从00:00变为23:59 business_hours['monday'] = 0x0000 0000 FFFF 0FFF F000 0000

为了让您busy_hours存储在一个相似的格式事件,只是&它们放在一起。

Exmample:

event_a = 0x0000 0000 00F0 0000 0000 0000 # 10:00 - 11:00 
event_b = 0x0000 0000 0000 07F8 0000 0000 # 13:15 - 15:15

busy_hours = event_a & event_b 

从busy_hours和business_hours你可以得到可用时间:

available_hours = business_hours&(busy_hours ^为0xFFFF FFFF FFFF FFFF FFFF FFFF)

异或(^)essentialy转化成busy_hours not_busy_hours。 安定()与business_hours not_busy_hours给我们的可用时间为一天。

该方案还可以很方便地使用小时比较了很多人。

all_available_hours = person_a_available_hours & person_b_available_hours & person_c_available_hours

然后找到适合可用小时的时间段。 你需要做这样的事情:将您的时间长度为类似十六进制数字的一个小时,其中的那些代表小时的时间段将覆盖所有的时间块。 所以没有尾随0的下一步右移数字。

实例是比更好的解释:0x1 =在> 15分钟后,0x3 =>半小时,为0x7 => 45分钟,0xF =>充分小时,...为0xFF => 2小时,等

一旦你这样做,你这样做:

acceptable_times =[]
(0 .. 24 * 4 - (#of time chunks time slot)).each do |i|
  acceptable_times.unshift(time_slot_in_hex) if available_hours & (time_slot_in_hex << i) == time_slot_in_hex << i
end

该范围的高端是有点乱的。 所以,让我们看看多一点吧。 我们不想太多次转移,不然我们就可以开始在频谱提前结束越来越误报。

24 * 4在每天24小时,其中每个由4个比特来表示。 - (#of time chunks in time slot)减1为您在时隙每次15分钟,我们要寻找的。 此值可以通过找到(Math.log(time_slot_in_hex)/Math.log(2)).floor + 1

其开始于一天结束时,检查每个时隙,早些时候在每次迭代时间块(在本例中15分钟)移动。 如果时隙可用它添加到可以接受的时间开始。 因此,当过程结束acceptable_times中出现的顺序进行排序。

最酷的是这个实现允许并入,使您的与会者可以在自己一天的忙碌时期,平分你休息后,他们可能会以其他方式忙着找时隙时隙。

这是给你写的辅助函数范围的阵列(即:[800..1200,1300..1700])之间进行转换和十六进制表示。 要做到这一点,最好的办法是封装行为的对象,并使用自定义的访问方法。 然后使用相同的对象来表示天,事件,繁忙时间,等等。这是没有内置此方案是如何安排的活动,使他们能够跨越天界的唯一的事情。



Answer 2:

要回答你的问题的标题,如果发现了一系列阵列包含范围:

ary = [800..1200, 1300..1700]

test = 800..830
p ary.any? {|rng| rng.include?(test.first) and rng.include?(test.last)}
# => true

test = 1245..1330
p ary.any? {|rng| rng.include?(test.first) and rng.include?(test.last)}
# => false

这可以写成

class Range
  def include_range?(r)
    self.include?(r.first) and self.include?(r.last)
  end
end


Answer 3:

好吧,我没有时间写了一个完整的解决方案,但似乎问题并不太难了我。 我砍死在一起,你可以用你的构建解决方案,以帮助下面原始的方法(可能要继承范围,而不是猴子打补丁,但是这会给你的想法):

class Range
  def contains(range)
    first <= range.first || last >= range.last
  end

  def -(range)
    out = []
    unless range.first <= first && range.last >= last
      out << Range.new(first, range.first) if range.first > first
      out << Range.new(range.last, last) if range.last < last
    end
    out
  end
end

可以遍历营业时间并查找包含像这样的事件之一:

event_range = event.start_time..event.end_time
matching_range = business_hours.find{|r| r.contains(event_range)}    

您可以构建这样的新阵列(伪,未测试):

available_hours = business_hours.dup
available_hours.delete(matching_range)
available_hours += matching_range - event_range

这应该是一个漂亮的可重复使用的方法。 当然,你需要的东西,你的问题的下一部分完全不同的,但是这是我的所有时间:)



文章来源: How to find if range is contained in an array of ranges?