🎄 13/25. How many days in the century match the condition?

Welcome to Day 13 of the Perl 6 One-Liner Advent Calendar! Today’s one-liner will be quite long, and it would be better to write it in two lines, but it will show a very nice feature of Perl 6’s Date objects: it can be easily used in a range.

Today, we are solving Problem 19 of the Project Euler. In essence, the task is to count Sundays between 1 January 1901 and 31 December 2000, which fall on the first of the months.

The Date object in Perl 6 implements the succ and prec methods, which are incrementing and decrementing the date. It is also possible to use two dates as the boundaries of a range:

say (
Date.new(year => 1901) ..^ Date.new(year => 2001)
).grep({.day == 1 && .day-of-week == 7}).elems

There are a few moments to comment here.

First, the two Date objects are created with a single named parameter, the year. This is possible because the signature of the constructor has default values for both the month and the day:

multi method new(
Date: Int:D() :$year!,
Int:D() :$month = 1, Int:D() :$day = 1,
:&formatter, *%_) {
. . .

So it’s easy to create a date for 1 January, but you can’t do that for the last day of the year. But Perl 6 has a nice range operator ..^, which excludes the right boundary and allows us to save quite a few characters (while we are not playing Perl 6 Golf yet :-).

The longer version, with all explicit parts of the dates, would then look like this:

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

You create a range and grep its values using a combined condition. Remember that there is no need to explicitly type $_ when you want to call a method on the default variable.

An alternative would be to use two greps with a star:

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

An exercise for you to make at home: Print the number of days left until the end of this Advent Calendar. See you tomorrow!

6 thoughts on “🎄 13/25. How many days in the century match the condition?”

  1. Thanks for the introduction to dates and a lot more too. I was going to challenge myself to working out every 2nd Sunday when I had a look at the docs and it was very easy to convert your one liner to second sunday…

    { .day-of-week == 7 && .weekday-of-month == 2}

    These are great, and a great jumping off point for more exploration…

Leave a Reply

Your email address will not be published. Required fields are marked *