我在这里查看了一些 SO 讨论,至少我没有看到这种观点。我正在尝试编写代码来计算给定资源的预订数量,我想在其中找到完成所有预订所需的最少资源数量。
让我们以酒店房间为例。鉴于我有以下预订
Chris 打来电话,想在他们为朋友预订的房间中添加一些房间,并想知道我有多少房间可用。
Rooms_available = Rooms_in_hotel - Rooms_booked
Rooms_booked
是我遇到问题的地方。似乎大多数问题(实际上是我的代码)只是着眼于重叠的日期。所以它会做这样的事情:
Booking.where("booking_end >= :start_check AND booking_start <= :end_check", { start_check: "July 4, 2021".to_date, end_check: "July 7, 2021".to_date})
此代码将返回 3。这意味着如果酒店理论上有 5 个房间,我会告诉 Chris 还有 2 个可用房间。
然而,虽然这种计数方法在技术上是准确的,但它忽略了有效重叠的可能性。也就是说,因为泰勒比帕特提前 4 天退房,他们都可以被“分配”到同一个房间。所以从技术上讲,我可以再给 Chris 提供 3 个房间。
所以我的问题是如何更准确地计算 Rooms_booked
以实现有效重叠(即有效的资源分配)?是否有使用 ActiveRecord 的查询,或者我在现有查询之上施加了什么计算?
答案 0 :(得分:0)
我不认为只有查询可以解决您的问题(或非常复杂的查询)。
我的想法是按 (booking_start, booking_end)
对 booking_start asc
进行分组(和计数),然后重新分配,例如如果有 2 个预订 July 15-July 19
和 3 个预订 July 10-July 11
那么我们只能重新分配 2 对,我们需要 3 个房间(July 15-July 19-July 10-July 11
有 2 个房间,July 10-July 11
有 1 个房间}}。
并在代码中重新分配而不是查询(我们可以通过选择一个狭窄的时间范围来优化)
# when Chris calls and would like to add some room(s) to their reservation for friends,
# and wonders how many available rooms.
# pick (start_time, end_time) so that the range time long enough that
# including those booking {n} month ago
# but no need too long or all the time
scope :booking_available_count, -> (start_time, end_time) {
group_by_time = \
Booking.where("booking_start >= ? AND booking_end <= ?", start_time, end_time)
.group(:booking_start, :booking_end).order(:booking_start).count
# result: {[booking_start, booking_end] => 1, [booking_start, booking_end] => 2, ... }
# in order booking_start ASC
# then we could re-assign from left to right as below
booked = 0
group_by_time.each do |(start_time, end_time), count|
group_by_time.each do |(assign_start_time, assign_end_time), assign_count|
next if end_time > assign_start_time
count -= assign_count # re-assign
break if count <= 0
end
booked += count if count > 0
end
# return number of available rooms
# allow negative number
Room.count - booked
}