So I’m back again for the Perl Weekly Challenge 009
First square number that has at least 5 distinct digits
Challenge #1 demonstrates again the power of lazy lists. I think generating results from lazy lists is pretty much becoming my favourite feature of Perl 6 by default – I find a use for it so frequently.
In this case we lazily generate a list from 0 to infinity –
(^∞) is basically
a term, right? – map it to a list of square numbers with
.map(* ** 2), and
then filter to numbers that have 5 unique digits.
To do this I used Bags (Sets would have worked too):
$digits is in this case 5 (the default for a value entered on the
command line in my solution). This will find all the Square numbers with at
least 5 digits, but it will literally take forever, so best to cut it short at
the first one with a
As usual, it’s on github if you care.
Varying styles of rank
Insert standard rant about vague specifications here. In the end, for test data
I got 20 copypasta from a random name generator and
Z=>pped them up to dice
rolls out of 10.
All the same, I went relatively all out on this one. Not because the challenge was hard, but because it’s a nice opportunity to (completely superfluously) play with multi dispatch.
RankMode is an enum of the ranking modes,
rank-dense>. Again, this is entirely unnecessary (actually I added it on at the
Now I can stick it in a multi dispatch prototype though (more stuff I added later):
$ basically indicates the first argument
is some kind of container
(thanks @raiph for the correction),
RankMode is as above, and
&? indicates the third argument is a
routine and is optional.
Following this (in source order - chronologically I did them first), I have three multi declarations that look like:
rank-dense substituted for
rank-standard in the
second and third subs’ signatures. This allows us to make apparently the same
function call but a different implementation is used depending on what
RankMode is given.
You might have noticed the
where constraint on the
@scores argument. This is
to ensure that a list of Pairs has been passed (or at least of somethings that
implement .value) with all the values being integers. This is actually a little
contrary to the flexibility provided by having a
&ranking call back, but
provides an early indication of something that would prevent the internals of
these functions working – and if we wanted to rank something with a different
structure later we could add another version of rank with another constraint and
both would still work.
The contents of these subroutines is very similar, where:
- First, it inverts the list of scores added to it (this is why we compare the
key in the default
&ranking) and create a Hash from this, meaning that keys of the
@scoresargument get grouped together according to their score.
- Then each group of Pairs is mapped to its ranking and spat out into an output array, with the Pair inverted back to its original order.
- Somewhere in this rank of the group or the one following it is determined in the way appropriate for each implementation.
I’m actually a little frustrated that when I tried to do this with a mapping
$n ranking variable would always be evaluated before anything was
mapped to the output, which made the
rank-standard routine behave the same as
rank-modified one; if anyone has any ideas on how to avoid this, I’d love
to hear them. The implementation was:
Anyway I also have a fourth multi-sub:
Which allows me to call
rank with a Hash, which it will turn into a list of
pairs, and then pass it on to the appropriate subroutine according to the given
$mode. Which is just kind of cool.
There’s not a single if statement in my code. You can check this on github
Again I’m opting out of this one, for the same reasons as last week, and also
because I started this challenge late owed to being at said
$day-job all week
(which I wasn’t before).
If I was to have a go at this one though, I’d probably use Cro::Http::Client though, because it will even marshal objects to JSON for me.