我认为这是位域的工作。不幸的是,这个解决方案将依赖于魔术数字、转换帮助程序和相当多的二进制逻辑,所以它不会很漂亮。但它将起作用并且非常有效。
这是我处理问题的方法:
将您的一天分解成合理的时间间隔。我将按照您的示例,将每个15分钟的时间块视为一个时间块(主要是因为它使示例保持简单)。然后,将每小时的可用性表示为十六进制数字。
例如:
0xF = 0x1111 => 整个小时都可以使用。
0xC = 0x1100 => 在第一个半小时内可用。
将24个这样的数字串在一起来表示一天。或者更少,如果您可以确定没有事件会发生在范围之外。以下示例假设为24小时。
从这一点开始,我已将长十六进制数拆分成单词以提高可读性
假设一天从00:00到23:59:
business_hours['monday'] = 0x0000 0000 FFFF 0FFF F000 0000
要获得busy_hours,您可以以类似的格式存储事件,并将它们全部&在一起。
例如:
event_a = 0x0000 0000 00F0 0000 0000 0000
event_b = 0x0000 0000 0000 07F8 0000 0000
busy_hours = event_a & event_b
从busy_hours和business_hours中,你可以获取可用的时间:
available_hours = business_hours & (busy_hours ^ 0xFFFFFFFFFFFFFFFFFFFF)
xor (^) 实际上将busy_hours翻译为not_busy_hours。使用not_busy_hours与business_hours进行and操作(&),我们可以得到当天的可用时间。
此方案还使比较多人的可用时间变得简单。
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 - (
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)
减去我们正在查找的时间段中每15分钟的一个检查。可以通过以下方法找到此值:(Math.log(time_slot_in_hex)/Math.log(2)).floor + 1
从一天的末尾开始,逐个检查每个时间段,每次迭代向前移动一个时间块(在本例中为15分钟)。如果时间段可用,则将其添加到可接受时间的开头。因此,当进程完成时,acceptable_times以发生顺序排序。
很酷的是,此实现允许时间段包含,这样您的参与者就可以在其一天中具有二分您要查找的时间段的繁忙期,并带有休息时间,在此期间他们可能会非常忙碌。
由您编写辅助函数将范围数组(即:[800..1200, 1300..1700])转换为十六进制表示法。最好的方法是将行为封装在对象中并使用自定义访问器方法。然后使用同一对象表示天、事件、繁忙小时等。此方案中唯一未建立的内容是如何安排事件,以使它们可以跨越天的边界。