当我在 sum_time 方法中使用 guard case 时,一个测试用例失败了,有什么建议吗?
When I used guard case in sum_time method one test case failed, any suggestions?
编写一个方法,对多个 24 小时时间值 (h:m:s) 求和。使用正则表达式验证时间。
输入输出格式:
例如:("11:23:07","22:53:45","0:23:23","23:45:56") -> "2 day & 10:26:11"
("11:23:07") -> "11:23:07"
我的代码因一个测试用例而失败,即
“24:01:10” “10:30:50”
解决方案:
require 'time'
# Time_Sum
class Time
KEY = /^(0\d|1\d|2[0-3]|\d):[0-5]\d?:[0-5]\d?$/
def to_seconds(timestamp)
timestamp.hour * 3600 + timestamp.min * 60 + timestamp.sec
end
def validate?(time_string)
time_string.match(KEY)
end
def sum_time(*time)
total_seconds = 0
time.each do |time_item|
timestamp = Time.parse(time_item) if validate?(time_item)
total_seconds += to_seconds(timestamp) if validate?(time_item)
'Invalid 24-hour time value'
end
display_results(total_seconds)
end
def display_results(total_seconds)
sum_time_string = ''
days = (total_seconds / (24 * 3600)).to_i
sum_time_string = "#{days} day & " if days > 0
sum_time_string + Time.at(total_seconds).utc.strftime('%H:%M:%S')
end
end
reader = Time.new
if ARGV.empty?
puts 'Please provide an input'
else
p reader.sum_time(*ARGV)
end
预期输出:
"Invalid 24-hour time value"
实际输出:
“10:30:50”
还有人可以建议更好的正则表达式密钥吗?
首先,我建议不要污染核心 Ruby class Time
。所需的方法可以包含在自定义 class 中,或者可能定义在 main
级别(正如我在下面所做的那样)。
我也不会使用 classes Time
或 DateTime
。处理字符串更容易。首先构建一个正则表达式,用于确定每个时间字符串是否有效。
VALID_TIME = /
\A # match beginning of string
(?: # begin non-capture of group
0?\d # optionally match a zero followed by a digit
| # or
1\d # match 1 followed by a digit
| # or
2[0-3] # match 2 followed by a digit 0, 1, 2 or 3
) # end non-capture group
(?: # begin a non-capture group
: # match a colon
[0-5] # match a digit 0, 1, 2, 3, 4 or 5
\d # match a digit
) # end non-capture group
{2} # execute the previous non-capture group twice
/x # free-spacing regex-definition mode
以free-spacing 模式编写正则表达式的优点是使它们成为self-documenting。这个正则表达式按照惯例写成:
/\A(?:0?\d|1\d|2[0-3])(?::[0-5]\d){2}/
我们的主要方法可能是 total_times
,向其传递一个或多个表示 twenty-four 小时的字符串。
def total_times(*time_strings)
seconds = tot_seconds(*time_strings)
days, hrs = seconds.divmod(24*3600)
hrs, mins = hrs.divmod(3600)
mins, secs = mins.divmod(60)
[days, hrs, mins, secs]
end
这首先调用一个方法 tot_seconds
,具有相同的参数。该方法 returns 自午夜以来经过的每次秒数的总和。获得总秒数后,重复使用 Integer#divmod 计算等效的天数、小时数、分钟数和秒数。
def tot_seconds(*time_strings)
time_strings.sum { |time_str| time_str_to_seconds(time_str) }
end
此方法将每个时间字符串传递给方法 time_str_to_seconds
,其中 returns 该时间字符串自午夜以来的秒数。
def time_str_to_seconds(time_str)
raise ArgumentError, "'#{time_str}' is an invalid 24-hour time value" unless
time_str.match?(VALID_TIME)
[3600, 60, 1].zip(time_str.split(':')).
reduce(0) { |tot,(n,s)| tot + n*s.to_i }
end
此方法首先检查时间字符串的有效性。如果发现它无效,则会引发异常。这似乎是进行有效性检查的最佳位置。如果发现字符串有效,则将其拆分为表示小时、分钟和秒的字符串,然后将其转换为整数并组合以获得秒数。
假设:
time_str = "9:35:08"
那么time_str_to_seconds
中的计算如下:
time_str.match?(VALID_TIME)
#=> true
a = time_str.split(':')
#=> ["9", "35", "08"]
b = [3600, 60, 1].zip(a)
#=> [[3600, "9"], [60, "35"], [1, "08"]]
b.reduce(0) { |tot,(n,s)| tot + n*s.to_i }
#=> 3600*9 + 60*35 + 1*8 => 34508
参见 String#match? and Array#zip。
现在让我们用一个例子来试试这个。
arr = total_times "2:33:41", "23:46:08"
#=> [1, 2, 19, 49]
我们可能会使用这些结果如下:
puts "%d day & %d:%2d:%2d" % arr
"1 day & 2:19:49"
在某些情况下,最好写成:
days, hrs, mins, secs = total_times "2:33:41", "23:46:08"
我们可以很容易地确认这些结果。
tot_secs = 2*3600 + 33*60 + 41 +
23*3600 + 46*60 + 8
#=> 94789
days, hrs = tot_secs.divmod(24*3600)
#=> [1, 8389]
hrs, mins = hrs.divmod(3600)
#=> [2, 1189]
mins, secs = mins.divmod(60)
#=> [19, 49]
[days, hrs, mins, secs]
#=> [1, 2, 19, 49]
另外两个例子:
total_times "11:23:07", "22:53:45", "0:23:23", "23:45:56"
#=> [2, 10, 26, 11]
total_times "24:01:10", "10:30:50"
#=> ArgumentError ('24:01:10' is an invalid 24-hour time value)
请注意,不一定要使用正则表达式来确定时间字符串的有效性。可以这样写:
time_str = "9:35:08"
hr, min, sec = time_str.split(':').map(&:to_i)
#=> [9, 35, 8]
(0..23).cover?(hr) && (0..59).cover?(min) && (0..59).cover?(sec)
#=> true
编写一个方法,对多个 24 小时时间值 (h:m:s) 求和。使用正则表达式验证时间。
输入输出格式: 例如:("11:23:07","22:53:45","0:23:23","23:45:56") -> "2 day & 10:26:11" ("11:23:07") -> "11:23:07"
我的代码因一个测试用例而失败,即 “24:01:10” “10:30:50”
解决方案:
require 'time'
# Time_Sum
class Time
KEY = /^(0\d|1\d|2[0-3]|\d):[0-5]\d?:[0-5]\d?$/
def to_seconds(timestamp)
timestamp.hour * 3600 + timestamp.min * 60 + timestamp.sec
end
def validate?(time_string)
time_string.match(KEY)
end
def sum_time(*time)
total_seconds = 0
time.each do |time_item|
timestamp = Time.parse(time_item) if validate?(time_item)
total_seconds += to_seconds(timestamp) if validate?(time_item)
'Invalid 24-hour time value'
end
display_results(total_seconds)
end
def display_results(total_seconds)
sum_time_string = ''
days = (total_seconds / (24 * 3600)).to_i
sum_time_string = "#{days} day & " if days > 0
sum_time_string + Time.at(total_seconds).utc.strftime('%H:%M:%S')
end
end
reader = Time.new
if ARGV.empty?
puts 'Please provide an input'
else
p reader.sum_time(*ARGV)
end
预期输出: "Invalid 24-hour time value" 实际输出: “10:30:50”
还有人可以建议更好的正则表达式密钥吗?
首先,我建议不要污染核心 Ruby class Time
。所需的方法可以包含在自定义 class 中,或者可能定义在 main
级别(正如我在下面所做的那样)。
我也不会使用 classes Time
或 DateTime
。处理字符串更容易。首先构建一个正则表达式,用于确定每个时间字符串是否有效。
VALID_TIME = /
\A # match beginning of string
(?: # begin non-capture of group
0?\d # optionally match a zero followed by a digit
| # or
1\d # match 1 followed by a digit
| # or
2[0-3] # match 2 followed by a digit 0, 1, 2 or 3
) # end non-capture group
(?: # begin a non-capture group
: # match a colon
[0-5] # match a digit 0, 1, 2, 3, 4 or 5
\d # match a digit
) # end non-capture group
{2} # execute the previous non-capture group twice
/x # free-spacing regex-definition mode
以free-spacing 模式编写正则表达式的优点是使它们成为self-documenting。这个正则表达式按照惯例写成:
/\A(?:0?\d|1\d|2[0-3])(?::[0-5]\d){2}/
我们的主要方法可能是 total_times
,向其传递一个或多个表示 twenty-four 小时的字符串。
def total_times(*time_strings)
seconds = tot_seconds(*time_strings)
days, hrs = seconds.divmod(24*3600)
hrs, mins = hrs.divmod(3600)
mins, secs = mins.divmod(60)
[days, hrs, mins, secs]
end
这首先调用一个方法 tot_seconds
,具有相同的参数。该方法 returns 自午夜以来经过的每次秒数的总和。获得总秒数后,重复使用 Integer#divmod 计算等效的天数、小时数、分钟数和秒数。
def tot_seconds(*time_strings)
time_strings.sum { |time_str| time_str_to_seconds(time_str) }
end
此方法将每个时间字符串传递给方法 time_str_to_seconds
,其中 returns 该时间字符串自午夜以来的秒数。
def time_str_to_seconds(time_str)
raise ArgumentError, "'#{time_str}' is an invalid 24-hour time value" unless
time_str.match?(VALID_TIME)
[3600, 60, 1].zip(time_str.split(':')).
reduce(0) { |tot,(n,s)| tot + n*s.to_i }
end
此方法首先检查时间字符串的有效性。如果发现它无效,则会引发异常。这似乎是进行有效性检查的最佳位置。如果发现字符串有效,则将其拆分为表示小时、分钟和秒的字符串,然后将其转换为整数并组合以获得秒数。
假设:
time_str = "9:35:08"
那么time_str_to_seconds
中的计算如下:
time_str.match?(VALID_TIME)
#=> true
a = time_str.split(':')
#=> ["9", "35", "08"]
b = [3600, 60, 1].zip(a)
#=> [[3600, "9"], [60, "35"], [1, "08"]]
b.reduce(0) { |tot,(n,s)| tot + n*s.to_i }
#=> 3600*9 + 60*35 + 1*8 => 34508
参见 String#match? and Array#zip。
现在让我们用一个例子来试试这个。
arr = total_times "2:33:41", "23:46:08"
#=> [1, 2, 19, 49]
我们可能会使用这些结果如下:
puts "%d day & %d:%2d:%2d" % arr
"1 day & 2:19:49"
在某些情况下,最好写成:
days, hrs, mins, secs = total_times "2:33:41", "23:46:08"
我们可以很容易地确认这些结果。
tot_secs = 2*3600 + 33*60 + 41 +
23*3600 + 46*60 + 8
#=> 94789
days, hrs = tot_secs.divmod(24*3600)
#=> [1, 8389]
hrs, mins = hrs.divmod(3600)
#=> [2, 1189]
mins, secs = mins.divmod(60)
#=> [19, 49]
[days, hrs, mins, secs]
#=> [1, 2, 19, 49]
另外两个例子:
total_times "11:23:07", "22:53:45", "0:23:23", "23:45:56"
#=> [2, 10, 26, 11]
total_times "24:01:10", "10:30:50"
#=> ArgumentError ('24:01:10' is an invalid 24-hour time value)
请注意,不一定要使用正则表达式来确定时间字符串的有效性。可以这样写:
time_str = "9:35:08"
hr, min, sec = time_str.split(':').map(&:to_i)
#=> [9, 35, 8]
(0..23).cover?(hr) && (0..59).cover?(min) && (0..59).cover?(sec)
#=> true