Week 326 : 2025-06-16
Part 1
So this is the first week I picked to start blogging about the challenge again and in someways it's pretty easy as Raku's Date object has a day of year function built in. So technically this works.
Date.new('2025-02-02').day-of-year.say;
But we can do a bit more. We really want to run it as a script so lets wrap it in a MAIN subroutine that gives us a simple but powerful commandline argument parsing.
sub MAIN( $d ) {
Date.new($d).day-of-year.say;
}
But rather than using Date.new we can make use of the fact that you can do that by casting your String as a Date like so.
sub MAIN( $d ) {
$d.Date.day-of-year.say;
}
Of course we want to make sure we're getting a string so we can update the signature to allow for that (even adding checking to make sure it looks like a date).
sub MAIN( Str $d where * ~~ /^ \d**4 "-" \d\d "-" \d\d ) {
$d.Date.day-of-year.say;
}
And you know that works. But... it's not very elegant. Of course when you cast a String to a Date you are going to get an error if the String is an invalid format and the same if your value are out of range so the check is over the top. But this then made me think why not just have MAIN accept a String that can be Cast in the signature to a Date. Add in some declarator block comments to give us nice usage and we have our final bit of code.
#| Display the day of the year for a given date
sub MAIN(
Date(Str) $d #= Date string in yyyy-mm-dd format
) {
$d.day-of-year.say;
}
Part 2
Once again this challenge is helped by the power of Raku and one of my favourite List methods rotor which is a very powerful way to take a list and break it down into smaller sublists. With this the simple solution to the challenge is as follows.
(1,2,3,4).rotor(2).map( -> ($x, $y) { |($y xx $x) }).say
We split the list into sublists of 2 items then use the xx list repetition operator to make new sublists which we then use the | operator to flatten these out into the outer list.
And that's nice and all but again we should wrap it in a MAIN subroutine and add some checking. In this case we want to slurp all the arguments given into a List and check the following.
- All the items are integers.
- It's an even length list.
- The 1st, 3rd and other odd positioned arguments are not negative (we'll allow for Zero though)
Taking all that into account we get the final result (with another use of rotor thrown in).
#|( Given a even length list of integers print a list where you
pick each adjacent pair (i, j) and replace it with j, i times.)
sub MAIN (
*@a where (
(@a.all ~~ Int)
&& (@a.elems %% 2)
&& (@a.rotor(1 => 1).map(*.Slip).all ~~ UInt)
) #= Even length list of Integers
) {
@a.rotor(2).map( -> ($x, $y) { |($y xx $x) }).say
}
Anyway, that's my thinking on solving this weeks challenge. Once again Raku came through in making it pretty simple.