【问题标题】:How to count bookings if allowing for efficient overlap如果允许有效重叠,如何计算预订
【发布时间】:2021-06-22 21:54:59
【问题描述】:

我在这里查看了一些 SO 讨论,至少我还没有看到这种观点。我正在尝试编写代码来计算给定资源的预订,我想在其中找到完成所有预订所需的最少资源数。

让我们以酒店房间为例。鉴于我有以下预订

  • 克里斯:7 月 4 日至 7 月 17 日
  • 拍摄日期:7 月 15 日至 7 月 19 日
  • 泰勒:7 月 10 日至 7 月 11 日

克里斯打来电话,想在他们为朋友预订的房间中添加一些房间,想知道我还有多少房间可用。

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 天退房,他们都可以被“分配”到同一个房间。所以从技术上讲,我可以为克里斯再提供 3 个房间。

所以我的问题是如何更准确地计算 Rooms_booked 以实现有效重叠(即有效的资源分配)?是否有使用 ActiveRecord 的查询或我在现有查询之上施加什么计算?

【问题讨论】:

    标签: ruby-on-rails ruby activerecord


    【解决方案1】:

    我不认为只有一个查询可以解决您的问题(或非常复杂的查询)。

    我的想法是按(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
    }
    

    【讨论】:

    • 谢谢@lamphan!这是一个好的开始,现在唯一的挑战是这允许冗余堆叠性。例如,如果 Chris 预订 7 月 4 日至 7 月 14 日,然后有第 4 个新人致电约 7 月 4 日至 17 日日期,则此代码将返回仅预订了 1 个房间,现在这是轻描淡写的。当代码在 7 月 4 日至 14 日的顶级订单中进行迭代时,它将在二级迭代中针对 7 月 15 日至 19 日的订单“堆叠”(减去计数)。但是,当代码随后迭代 7 月 10 日至 11 日的顶级订单时,它还将与 7 月 15 日至 19 日的订单“堆叠”
    • 我正在努力想一些不会让这件事变得疯狂复杂的修改
    • 我当前的解决方案... 1)认识到您的代码基本上是在询问,是否可以将顶层的给定日期集堆叠到其他东西上(迭代第二层),2)这会导致错误,其中 2 个顶级事物可以堆叠到同一个二级事物上,所以 3)我只是颠倒了它,并编写了代码,这样被问到的问题是,顶级事物可以接受任何其他二级事物。这种方式break也很方便,因为一旦顶层的东西已经采取了别的东西,它就不能多余地堆叠其他东西......这太罗嗦了我会粘贴代码
    • 我在 2 个嵌套迭代中的代码:if start_time &gt; assign_end_time; count -= assign_count; break if count &lt;= 0; end。到目前为止,这个已经通过了我的规格,将继续查看是否还有其他问题
    • 也是次要的,但我不认为starting_date的顺序是必要的?因为无论如何我们已经在迭代......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-01
    • 1970-01-01
    相关资源
    最近更新 更多