Raku Books / Raku One-Liners / Working with Dates
Another solution of the same prob- lem
Here is another solution of the problem. The task was to count all Sundays that fall on the first of the month in the XX century.
Last time, we were scanning all the days in the whole century,
selecting the ones that are Sundays (.day-of-week == 7) and
are the first of the month
(.day == 1).It is possible to make a more efficient algorithm. As we are only interested in the first days of the month, there is no need to scan all 36525 days for 100 years. Looking at only 1200 days that are the first day of each month between 1901 and 2000 is enough.
So, we need two nested loops: over the years and over the months. Do
we need two fors? Not necessarily. Let’s use the
X operator (see Chapter 6 for more details on it).
And here is our new one-liner:
(gather for 1901..2000 X 1..12 {
take Date.new(|@_, 1)
}).grep(*.day-of-week == 7).elems.say;The for 1901..2000 X 1..12 loop goes over each month in
the XX century. For each, we create a Date object by
calling a constructor with three arguments.
Notice that inside the loop, you can use both $_[0] and
$_[1], and @_[0] and @_[1]. In
the first case, the $_ variable contains a list of two
elements, while it is an array @_ in the second one. The
shortest code is achieved if you are just using a dot to call a method
on the topic (default) variable: .[0] and
.[1].Instead of Date.new(|@_, 1), you can type
Date.new(.[0], .[1], 1). The |@_ syntax is
used to unroll an array, as otherwise Raku thinks that you are passing
an array as a first argument.
All first days of the months are collected in a sequence with the
help of the gather—take pair.
The final step is a grep as before, but this time we
only need to select Sundays, so a single *.day-of-week == 7
condition is enough.
The call of the elems method returns the number of the
elements in the list, which is the number of Sundays that we are looking
for. Thus, print it with say.
Based on a very relevant comment from a reader, here’s even better
and simpler way of the solution, where the + prefix
operator is used to cast a list to its length:
say +(1901..2000 X 1..12).map(
{Date.new(|@_, 1)}
).grep(*.day-of-week == 7);Course navigation
← How many days in the century match the condition? | Raku Syntax →