🎄 14/25. 昨天问题的另一个解决方案

欢迎来到 Perl 6 One-Liner Advent Calendar 的第14天!今天,我们正在提出我们昨天解决的问题的另一个答案。任务是计算二十世纪第一个月的所有星期日。

昨天,我们只扫描了整个世纪的所有日子,选择星期日( .day-of-week == 7)并且是本月的第一天(.day == 1)。

可以制作更有效的算法。由于我们只对本月的第一天感兴趣,因此无需在100年内扫描所有36525天,而只需要扫描100天,这是1901年到2000年之间每个月的第一天。

因此,我们需要两个嵌套循环:年和月。我们需要两个 for 吗?不必要。我们使用 X 运算符;我们从以前的出版帖子中熟悉它。

这是我们今天的单行:

1
2
3
(gather for 1901..2000 X 1..12 {
take Date.new(|@_, 1)
}).grep(*.day-of-week == 7).elems.say;

for 1901..2000 X 1..12 循环在遍历二十世纪的每个月份。对于每个循环变量,我们通过调用具有三个参数的构造函数来创建 Date 对象。

请注意,在循环内部,您可以同时使用 $_[0]$_[1],以及 @_[0]@_[1]。在第一种情况下,$_ 变量包含两个元素的列表,而在第二种情况下,它是一个数组 @_。如果您只是使用点来调用主题(默认)变量上的方法,则可以实现最短的代码:.[0].[1]

您可以键入 Date.new(.[0], .[1], 1) 代替 Date.new(|@_, 1)|@_ 语法用于展开数组,否则 Perl 6 会认为您将数组作为第一个参数传递。

gather-take 对儿的帮助下,将这些月份的所有第一天收集到序列中。

最后一步是昨天的 grep,但这次我们只需要选择星期日,所以单个 *.day-of-week == 7 条件就足够了。

elems 方法的调用返回列表中元素的数量,即我们正在寻找的星期日数量。因此,请用 say 打印出来。

一个新的想法和一个新的答案应该让你在这个 One-Liner 日历中至少有一天感到高兴,直到明天的帖子!