gpt4 book ai didi

ruby - 无法遍历 Ruby 中的 Time 对象

转载 作者:太空宇宙 更新时间:2023-11-03 17:03:30 25 4
gpt4 key购买 nike

我正在编写一个让用户选择日期的约会表单。然后它会获取日期并对照 Google 日历检查在从上午 10:00 到下午 5:00 的 30 分钟时间间隔范围内该日期有哪些时间段可用。

在我的日历类中,我有一个 available_times 方法:

def available_times(appointment_date)
appointment_date_events = calendar.events.select { |event| Date.parse(event.start_time) == appointment_date }

conflicts = appointment_date_events.map { |event| [Time.parse(event.start_time), Time.parse(event.end_time)] }
results = resolve_time_conflicts(conflicts)
end

此方法获取日期并获取该日期每个事件的 start_timeend_time。然后调用 resolve_time_conflicts(conflicts):

def resolve_time_conflicts(conflicts)
start_time = Time.parse('10:00am')
available_times = []
14.times do |interval_multiple|
appointment_time = (start_time + interval_multiple * (30 * 60))
available_times << appointment_time unless conflicts.each{ |conflict| (conflict[0]..conflict[1]).include?(appointment_time)}
end
available_times
end

当我尝试遍历冲突数组时,抛出“无法遍历时间”错误。我试图在冲突数组上调用 to_enum 但我仍然遇到同样的错误。

我在 SO 上看到的所有其他问题都引用了 step 方法,这似乎不适用于这种情况。

更新:

Thanks @caryswoveland and @fivedigit. I combined both of your answers, which were very helpful for different aspects of my solution:

def available_times(appointment_date)
appointment_date_events = calendar.events.select { |event| Date.parse(event.start_time) == appointment_date }

conflicts = appointment_date_events.map { |event| DateTime.parse(event.start_time)..DateTime.parse(event.end_time) }
results = resolve_time_conflicts(conflicts)
end

def resolve_time_conflicts(conflicts)
date = conflicts.first.first
start_time = DateTime.new(date.year, date.month, date.day, 10, 00).change(offset: date.zone)
available_times = []
14.times do |interval_multiple|
appointment_time = (start_time + ((interval_multiple * 30).minutes))
available_times << appointment_time unless conflicts.any? { |conflict| conflict.cover?(appointment_time)}
end
available_times
end

最佳答案

异常

@fivedigit 已经解释了引发异常的原因。

其他问题

你需要 any? 你有 each:

appointment_times = []
#=> []
appointment = 4
#=> 4
conflicts = [(1..3), (5..7)]
#=> [1..3, 5..7]

appointment_times << 5 unless conflicts.each { |r| r.cover?(appointment) }
#=> nil
appointment_times
#=> []

appointment_times << 5 unless conflicts.any? { |r| r.include?(appointment) }
#=> [5]
appointment_times
#=> [5]

我建议你将 appointment_time 隐藏到一个 Time 对象,使 conflicts 和元素数组 [start_time, end_time],然后将 appointment_time 与端点进行比较:

...unless conflicts.any?{ |start_time, end_time|
start_time <= appointment_time && appointment_time <= end_time }

旁白:Range#include?仅在端点为“数字”时查看端点(如 Range#cover? 所做的)。 Range#include? 只需要在端点是Time 对象时查看,但我不知道Ruby 是否将Time 对象视为“数字” ”。我想人们可以看看源代码。有人知道吗?

替代方法

我想建议一种不同的方法来实现您的方法。我将通过一个例子来做到这一点。

假设约会以 15 分钟为单位进行,第一个时间段为上午 10:00 至 10:15,最后一个时间段为下午 4:45 至 5:00。 (当然, block 可以更短,持续时间小至 1 秒。)

设上午 10:00-10:15 为第 0 区,上午 10:15-10:30 为第 1 区,依此类推,直到第 27 区,下午 4:45-5:00。

接下来,将 conflicts 表示为 block 范围数组,由 [start, end] 给出。假设有约会:

10:45am-11:30am (blocks 3, 4 and 5)
1:00pm- 1:30pm (blocks 12 and 13)
2:15pm- 3:30pm (blocks 17, 18 and 19)

然后:

conflicts = [[3,5], [12,13], [17,19]]

您必须编写一个返回冲突的方法reserved_blocks(appointment_date)

剩余代码如下:

BLOCKS = 28
MINUTES = ["00", "15", "30", "45"]
BLOCK_TO_TIME = (BLOCKS-1).times.map { |i|
"#{i<12 ? 10+i/4 : (i-8)/4}:#{MINUTES[i%4]}#{i<8 ? 'am' : 'pm'}" }
#=> ["10:00am", "10:15am", "10:30am", "10:45am",
# "11:00am", "11:15am", "11:30am", "11:45am",
# "12:00pm", "12:15pm", "12:30pm", "12:45pm",
# "1:00pm", "1:15pm", "1:30pm", "1:45pm",
# "2:00pm", "2:15pm", "2:30pm", "2:45pm",
# "3:00pm", "3:15pm", "3:30pm", "3:45pm",
# "4:00pm", "4:15pm", "4:30pm", "4:45pm"]

def available_times(appointment_date)
available = [*(0..BLOCKS-1)]-reserved_blocks(appointment_date)
.flat_map { |s,e| (s..e).to_a }
last = -2 # any value will do, can even remove statement
test = false
available.chunk { |b| (test=!test) if b > last+1; last = b; test }
.map { |_,a| [BLOCK_TO_TIME[a.first],
(a.last < BLOCKS-1) ? BLOCK_TO_TIME[a.last+1] : "5:00pm"] }
end

def reserved_blocks(date) # stub for demonstration.
[[3,5], [12,13], [17,19]]
end

让我们看看我们得到了什么:

available_times("anything") 
#=> [["10:00am", "10:45am"],
# ["11:30am", "1:00pm"],
# [ "1:45pm", "2:15pm"],
# [ "3:00pm", "5:00pm"]]

解释

这是正在发生的事情:

appointment_date = "anything" # dummy for demonstration

all_blocks = [*(0..BLOCKS-1)]
#=> [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
# 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27]
reserved_ranges = reserved_blocks(appointment_date)
#=> [[3, 5], [12, 13], [17, 19]]
reserved = reserved_ranges.flat_map { |s,e| (s..e).to_a }
#=> [3, 4, 5, 12, 13, 17, 18, 19]
available = ALL_BLOCKS - reserved
#=> [0, 1, 2, 6, 7, 8, 9, 10, 11, 14, 15, 16, 20, 21, 22, 23, 24, 25, 26, 27]

last = -2
test = false
enum1 = available.chunk { |b| (test=!test) if b > last+1; last = b; test }
#=> #<Enumerator: #<Enumerator::Generator:0x00000103063570>:each>

我们可以将它转换成一个数组,看看如果 map 没有跟随,它将传递给 block 的值是什么:

enum1.to_a
#=> [[true, [0, 1, 2]],
# [false, [6, 7, 8, 9, 10, 11]],
# [true, [14, 15, 16]],
# [false, [20, 21, 22, 23, 24, 25, 26, 27]]]

Enumerable#chunk对枚举器的连续值进行分组。它通过对 test 的值进行分组并在遇到非连续值时在 truefalse 之间翻转其值来实现。

enum2 = enum1.map
#=> #<Enumerator: #<Enumerator: (cont.)
#<Enumerator::Generator:0x00000103063570>:each>:map>

enum2.to_a
#=> [[true, [0, 1, 2]],
# [false, [6, 7, 8, 9, 10, 11]],
# [true, [14, 15, 16]],
# [false, [20, 21, 22, 23, 24, 25, 26, 27]]]

您可能会将 enum2 视为“复合”枚举器。

最后,我们转换传递到 block 中的每个 enum2 值的第二个元素( block 变量 a,等于 [0,1 ,2](对于传递的第一个元素)到一个表示为 12 小时时间的范围。 enum2 的每个值的第一个元素(truefalse)没有被使用,所以我用下划线替换了它的 block 变量.这提供了所需的结果:

enum2.each { |_,a|[BLOCK_TO_TIME[a.first], \
(a.last < BLOCKS-1) ? BLOCK_TO_TIME[a.last+1] : "5:00pm"] }
#=> [["10:00am", "10:45am"],
# ["11:30am", "1:00pm"],
# [ "1:45pm", "2:15pm"],
# [ "3:00pm", "5:00pm"]]

关于ruby - 无法遍历 Ruby 中的 Time 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25650236/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com