This is my response to The Weekly Challenge #332.
YYYY-MM-DD
.
Input: $date = "2025-07-26"
Output: "11111101001-111-11010"
Example 2:
Input: $date = "2000-02-02"
Output: "11111010000-10-10"
Example 3:
Input: $date = "2024-12-31"
Output: "11111101000-1100-11111"
#! /usr/bin/env raku
unit sub MAIN ($date where $date ~~ /^ \d\d\d\d \- \d\d \- \d\d $/); # [1]
say $date.split('-').map( *.fmt('%b') ).join('-'); # [2]
[1] Ensure a date-like string as input, without validating it further.
[2] Split the string on the dashes, then use map
to convert
each number to binary format with fmt
(and %b
for binary), the
method form of sprintf
. And finally we add the three parts togeter
with dashes and print the result.
See docs.raku.org/routine/fmt for more information about fmt
.
Running it:
$ ./binary-date "2025-07-26"
11111101001-111-11010
$ ./binary-date "2000-02-02"
11111010000-10-10
$ ./binary-date "2024-12-31"
11111101000-1100-11111
Looking good.
Verbose mode did not fit in with this practically oneliner format.
An example of «garbage in, garbage out»:
$ ./binary-date "2025-13-32"
11111101001-1101-100000
Let us get rid of the garbage:
File: binary-date-try
#! /usr/bin/env raku
unit sub MAIN ($date where $date ~~ /^ \d\d\d\d \- \d\d \- \d\d $/);
try Date.new($date) # [1]
&& say $date.split('-').map( *.fmt('%b') ).join('-');
[1] The try
prevents the program from crashing on an illegal
date. The binary date is printed for legal dates only, i.e. nothing is printed
for invalid input.
See docs.raku.org/routine/try for more information about try
.
$ ./binary-date-try 2025-12-00
$ ./binary-date-try 2025-12-01
11111101001-1100-1
$ ./binary-date-try 2025-12-31
11111101001-1100-11111
$ ./binary-date-try 2025-13-31
Input: $str = "weekly"
Output: false
w: 1 time
e: 2 times
k: 1 time
l: 1 time
y: 1 time
The letter 'e' appeared 2 times i.e. even.
Example 2:
Input: $str = "perl"
Output: true
Example 3:
Input: $source = "challenge"
Output: false
#! /usr/bin/env raku
unit sub MAIN ($str where $str.chars > 0, :v(:$verbose)); # [1]
my $bag = $str.comb.grep(/<[a..z A..Z]>/).Bag; # [2]
my @even = $bag.grep( *.value %% 2 )>>.key; # [3]
if $verbose
{
say ": Bag: { $bag.raku }";
say ": Even letters: { @even.join(", ") }";
}
say @even.elems == 0; # [4]
[1] Ensure at least one character.
[2] Split the string into a list of separate characters. The
challenge says that the input is a string, but that we are going to count
letters only, so I use grep
to get rid of any non-letters in the
input. Finally we apply Bag
to get a hash like structure where the
keys are the unique letters, and the values are the frequency
[3] We use grep
to get the characters that occured an even number
of times (divisible by two; %% 2
). The >>.key
part gets the
key (i.e. letter) from each entry in the Bag, leaving us with a list of
letters that occured an even number of times.
[4] Success if the list is empty, and failure otherwise.
Running it:
$ ./odd-letters 'weekly'
False
$ ./odd-letters 'perl'
True
$ ./odd-letters 'challenge'
False
Looking good.
With verbose mode:
$ ./odd-letters -v 'weekly'
: Bag: ("k"=>1,"e"=>2,"l"=>1,"w"=>1,"y"=>1).Bag
: Even letters: e
False
$ ./odd-letters -v 'perl'
: Bag: ("l"=>1,"e"=>1,"r"=>1,"p"=>1).Bag
: Even letters:
True
$ ./odd-letters -v 'challenge'
: Bag: ("n"=>1,"a"=>1,"h"=>1,"g"=>1,"l"=>2,"c"=>1,"e"=>2).Bag
: Even letters: l, e
False
Some more, testing non-letters as well:
$ ./odd-letters -v 'raku'
: Bag: ("u"=>1,"r"=>1,"a"=>1,"k"=>1).Bag
: Even letters:
True
$ ./odd-letters -v 'raku!!!!!!!'
: Bag: ("a"=>1,"u"=>1,"k"=>1,"r"=>1).Bag
: Even letters:
True
Looking good.
And that's it.