-2

我需要在 Ruby 中将当月的日历输出到控制台。结果应该类似于类 UNIX 系统上的 ncal。我找到了 C++ 的解决方案,但无法适应 Ruby。到目前为止,我只意识到我需要使用嵌套循环来输出高度和宽度。告诉我往哪个方向移动?

require 'date'
days = %w[Mun Tue Wed Thu Fri Sat Sun]
puts "    #{Date::MONTHNAMES[Date.today.month]} #{Date.today.year}"
i = 0
start_month = (Date.today - Date.today.mday + 1).strftime("%a")

while i < days.size
  print days[i]
  j = 1

  while j <= 31
    if days[i] == start_month 
      print " #{j}"
    end
    j += 7
  end

  i += 1
  puts
end
4

3 回答 3

1

到目前为止,我将采用您的解决方案,并尝试就如何处理它给出一些具体的指示 - 但当然,通常有许多不同的方法可以解决这个问题,所以这绝不是唯一的方法!

第一个关键问题(如您所知!)是您打印从本月 1 日开始的行的内容,因为这条线:

if days[i] == start_month

坚持当前的整体设计,我们知道我们需要为每一行打印一些东西,所以显然这样的条件是行不通的。让我们尝试删除它。

首先,以数字而不是字符串的形式知道月份从一周中的哪一天开始会更方便,因此我们可以轻松计算与另一天的偏移量。让我们这样做:

# e.g. for 1st July 2021 this was a Thursday, so we get `4`.
start_of_month_weekday = (Date.today - Date.today.mday + 1).cwday

接下来(这也是关键的一步!),我们可以利用上面的信息找出“星期几,星期几?”

这是该计算的第一个版本,到目前为止已合并到您的解决方案中:

require 'date'
days = %w[Mon Tue Wed Thu Fri Sat Sun]
puts "    #{Date::MONTHNAMES[Date.today.month]} #{Date.today.year}"
i = 0
# e.g. for 1st July 2021 this was a Thursday, so we get `4`.
start_of_month_weekday = (Date.today - Date.today.mday + 1).cwday

while i < days.size
  print days[i]
  day_of_month = i - start_of_month_weekday + 2 # !!!

  while day_of_month <= 31
    print " #{day_of_month}"
    day_of_month += 7
  end

  i += 1
  puts
end

这输出:

    July 2021
Mon -2 5 12 19 26
Tue -1 6 13 20 27
Wed 0 7 14 21 28
Thu 1 8 15 22 29
Fri 2 9 16 23 30
Sat 3 10 17 24 31
Sun 4 11 18 25

不错!现在我们到了某个地方!

我会让你弄清楚其余的......但这里有一些线索,我接下来要解决的问题:

  1. print " #{day_of_month}"如果天数小于 1,此代码需要打印一个“空格”。这可以通过一个简单的if语句来完成。
  2. 同样,由于您希望此日历在网格中整齐排列,因此您需要此代码始终打印两个字符宽的东西。sprintf是你的朋友在这里!查看页面一半左右的“宽度示例”。
  3. 您已经硬编码31了该月的天数。当然,这应该是固定的。(使用Date图书馆!)
  4. 有趣的是,您如何strftime("%a")在一个地方使用,但在上面一行中却笨拙地构建了日历标题! 查看格式化日期的文档;它非常灵活。我认为您可以使用:Date.today.strftime("%B %Y").
  5. 如果您想为当月的当天添加一些颜色(或背景颜色?),请考虑执行类似操作,或使用库来协助
  6. 使用while循环可以正常工作,但非常不可靠。在 99% 的情况下,Ruby 有更好的工具来完成这项工作;这是一种非常有表现力的语言——迭代器为王!(我猜您在 ruby​​ 之前首先学习了另一种语言?看到while循环和/或for循环是您对另一种语言更熟悉的一种死赠品。)while i < days.size您可以使用外部 while 循环()而不是days.each_with_index. 而不是内部的while循环(while j < 31),你可以使用day_of_month.step(31, 7)(这太酷了!!)。
于 2021-07-25T11:58:36.663 回答
0

感谢您的帮助,实际上是 10 个小时,多亏了您,我才弄明白。对于最初提出的问题,我再次道歉。

在提示的帮助下,我组装了这样一个解决方案。

require 'date'
days = %w[Mon Tue Wed Thu Fri Sat Sun]
p days
blanks = Date.new(2021,7,1).wday - 1

blanks.times do
  days.push(' ')
end

days_in_month = Date.new(2021, 7, -1).day
days_in_month
day = 1

while day <= days_in_month
  days.push(day)
  day += 1
end 

unless (days.size % 7) == 0
 days.push(' ')
end 

days.join(', ')
new_arr = days.each_slice(7).to_a
 puts"Массив дней: #{new_arr}"

for i in 0...7
 
 for j in 0...new_arr.size
  print "  #{new_arr[j][i]}"
 end
puts
end
于 2021-07-25T18:56:59.223 回答
0

这是一种方式:

  • 构造一个一维数组,从 daynames (Mon Tue ...) 开始。
  • 找出一种方法来确定该月开始有多少“空白”(这些是上个月的几天。wday可能会有所帮助)。将该数量的空字符串附加到数组中。
  • 确定该月有多少天(提示 Date.new(2021,7,-1),并将所有这些天数附加到数组中。
  • 将空字符串附加到数组,直到数组的大小可以被 7 整除(或者更好,计算)。如果您要跳过最后一个项目符号,请跳过此内容。
  • 将此数组的所有元素转换为大小为 3 或类似大小的右调整字符串。
  • 用于each_slice(7)将数组切片为数周。
  • 如果需要,transpose可以使用此周片数组来模拟 ncal 输出。
于 2021-07-24T23:00:10.800 回答