Week 329 : 2025-06-30
Endings
Before I go on I've just like to say RIP MST I met him a couple of times and interacted with him a few more. But I worked with his code a lot and it's made my life and the world better. I hope he can be remembered with positivity.
Elephants : Part 1
So for our first part of the challenge we are given a string made of lower case letters and numbers, so I'll quickly
whip up a ValidInput
to check for that.
subset ValidInput of Str where /^ <[a..z 0..9]>+ $/;
I'll also put together a test suite that I can run using the -t
or --test
flags. (One of those things I'd forgotten about in previos code if you check it out. Doh.
multi sub MAIN(:t(:$test)) is hidden-from-USAGE {
use Test;
is counter-string("the1weekly2challenge2"), (1,2);
is counter-string("go21od1lu5c7k"), (21,1,5,7);
is counter-string("4p3e2r1l"), (4,3,2,1);
done-testing;
}
There's a couple of things I'lll point out here, the use of is hidden-from-USAGE
which means that the test option won't appear in the auto generated usage output. I find it quite
helpful and was very happy when it was added to Raku. Also we only load the Test module within
our test suite which is nice it only exists within that lexical scope.
Ok enough faffing around what do we ween to do? Swap all the letters with spaces and then return a list of numbers. Taking into account that numbers in a group, like the 21 in the second test, are one integer. Also we only count any number in the list once, so there is only 1 number 2 in the first example. So this is simple enough.
sub counter-string( ValidInput $in is copy ) {
$in ~~ s:g/ (<[a..z]>) / /;
return $in.split(/" "+/).grep(* !~~ "").unique.map(*.Int);
}
So we take our string and replace each letter in it with a space, using the :g
adverb
to replace each match. Then we split the string on spaces, remove empty strings and throw out
duplicates. Finally (though we don't really have to) we cast the results to the Int
Class because that's what it asked for an I was in literal mode. Finally we can make a nice
MAIN
block to wrap this.
#|(Given a string made of lowercase letter and numbers
print a list of the unique numbers in it in order)
multi sub MAIN (
ValidInput $str #= A string made up of lowercase letters and number
) {
counter-string($str).join(", ").say;
}
But what, you might ask has this got to do with Elephants? Well there's one in the room and a couple of things I needed to bear in mind. After submitting my PR for this weeks challenge on Monday I saw there were a few other Raku submissions so I took a gander and all the ones I looked at had done the same thing for part one.
$str.comb( /\d+/ ).unique;
And as soon as I saw that I realised two things, firstly I finally understood
comb
. I've pretty much only ever used it as a way to split a string into it's parts.
But now I see what it's doing, making a list of all the matching items. But I also realised I'd
got to literal, a problem that I'm sure we've all fallen into at times, I got caught up attempting
to replicate the exact description of the requirements (with replacing letters with spaces) and
not focussing on the end result (find all the unqiue integers in the string). I'd missed the
Elephant in the room, and it's not that big a room I do this in. Oh well, live and learn I guess.
Explanations : Part 2
So this time we've got a valid input defined as a string of upper and lower case letters so I'll quickly whip up a subset for it and a test suite.
# Tests fired if called with test parameter
multi sub MAIN(:t(:$test)) is hidden-from-USAGE {
use Test;
is nice-string("YaaAho"), "aaA";
is nice-string("cC"), "cC";
is nice-string("A"), "";
done-testing;
}
subset ValidInput of Str where m/^ <[a..z A..Z]>+ $/;
So our object is to remove from the string any letter that is not found in both upper and lower case within the string. So as my brain often does it looked at this and thought "This looks like a job for Sets!". My brain is a strange thing at times. But it also had a point.
If we get a list of the letters in the string. Then get two sets, one being the difference between the letters and the uppercase letters and the second being the difference between the lettrs and the lowercase letters we can then check each letter of the alphabet in turn. If it's found in it's two different cases* within the sets then we note this in a hash.
After that is' a simple case of grepping for letters that appear in the hash and Ta Da!
sub nice-string( ValidInput $str ) {
my @letters = $str.comb;
my $upper = @letters ∩ ("A".."Z");
my $lower = @letters ∩ ("a".."z");
my %both;
for "a".."z" -> $str {
if ($str.uc ∈ $upper) && ($str ∈ $lower) {
%both{$str} = True;
%both{$str.uc} = True;
}
}
return @letters.grep( { %both{$_} } ).join("");
}
#|(Given a string made of upper and lower case
letter print the string with any letters not
included in both cases removed)
multi sub MAIN(
ValidInput $str #= A String made of lower and uppercase letters
) {
nice-string($str).say;
}
So there we go I explained my code but there is another explanation to be made, whay have I changed the title structure for this blog. Well I blame Mohammad, specifically the wonderful Mohammad Anwar who has done an amazing job running the Weekly Challange for years now. You see there's a part in the challenge each week listing blog posts... but it's specifically Blogs with Creative Title so of course I had to rise to this second challenge and up my blogging and title game. And there we go, a bit more rambling and a snappy title. I hope you have a great weekend and are looking forward to next weeks challenge.
An Aside
While I was writing that section of the post my brain went off on a tangent about why it's called upper and lower case and I figured I'd tip that hat to one of my favourite authors and pop it here as footnote. For those of you who don't know when print was arranged by hand using movable type the letters were arranged in two large wooden cases. In the largest lower case you had the smaller letters, these were easier for the typesetter to reach. If he needed a capital letter he would reach up to the smaller upper case to get one.
But erudite readers that you are I'm sure you knew that.