🎄 13/25. 本世纪多少天符合条件?
— 焉知非鱼欢迎来到 Raku One-Liner Advent Calendar 的第13天!今天的单行将很长,最好用两行编写,但它会显示 Raku 的 Date 对象的一个非常好的功能:它可以很容易地在一个范围内使用。
今天,我们正在解决欧拉项目的问题19。从本质上讲,任务是计算在1901年1月1日至2000年12月31日期间的星期日,这是在第一个月。
Raku 中的 Date 对象实现了 succ
和 prec
方法,它们递增和递减日期。也可以使用两个日期作为范围的边界:
say (
Date.new(year => 1901) ..^ Date.new(year => 2001)
).grep({.day == 1 && .day-of-week == 7}).elems
在这里评论一下。
首先,使用单个命名参数(year
)创建两个 Date 对象。这是可能的,因为构造函数的签名具有月和日的默认值:
multi method new(
Date: Int:D() :$year!,
Int:D() :$month = 1, Int:D() :$day = 1,
:&formatter, *%_) {
. . .
}
因此,创建1月1日的日期很容易,但是在一年的最后一天你不能这样做。但是 Raku 有一个很好的范围运算符 ..^
,它排除了右边界并允许我们节省相当多的字符(而我们还没有玩 Raku Golf :-)。
具有日期的所有显式部分的较长版本将如下所示:
say (
Date.new(year => 1901, month => 1, day => 1) ..
Date.new(year => 2000, month => 12, day => 31)
).grep({.day == 1 && .day-of-week == 7}).elems
您可以使用组合条件创建范围并 grep
其值。请记住,当您要在默认变量上调用方法时,无需显式键入 $_
。
另一种方法是使用带有星号的两个 grep
s:
say (
Date.new(year => 1901, month => 1, day => 1) ..
Date.new(year => 2000, month => 12, day => 31)
).grep(*.day == 1).grep(*.day-of-week == 7).elems
给你留个家庭作业:打印此 Advent 日历结束前剩余的天数。明天见!