This post is part of a series on Mohammad Anwar’s excellent Weekly Challenge, where hackers submit solutions in Perl, Raku, or any other language, to two different challenges every week. (It’s a lot of fun, if you’re into that sort of thing.)
Yes, it’s been a long while! Many a curveball has been thrown at my face. This week’s tasks are pretty quick and easy, so let’s dive right in.
Count Even Digits Number
The first task is simple. Given a list of integers, return the count of integers that have an even number of digits. So, for example, (10, 1, 111, 24, 1000) has 3 values with an even number of digits.
I was in a regex-y mood, so here’s what I came up with (Perl):
sub even_re { ()= "@_" =~ /\b(\d\d)+\b/g }
The pattern is simple: match two digits (\d\d)
one or more times (+
), separated by a word boundary (\b
). That is matched against "@
_"
, which interpolates to the list, separated by $"
.
Since we use the /g
(global) match, we get all matches back. The ()=
pseudo-operator turns that into the count of matches. If that were being assigned to a variable, you’d see it written like this instead:
$result =()= $var =~ /pattern/g
Raku
In Raku, I decided to do the slightly more sane thing and grep
the list rather than interpolating first:
sub even_re { +@_.grep(/^(\d\d)+$/) }
Without the +
, we would return the list of matches. The +
forces it to a scalar, giving us the count of matches instead.
Sum of Values
Task 2 has us take in a list of integers and a number $k
, and add up the integers whose index in the array contain $k
ones. So, for example, given $k = 1
and @ints = (2, 5, 9, 11, 3)
, we have to look at the binary representation of the array indicies:
The bold rows (values: 5, 9, 3) have a base-2 index containing only one 1, so the result is 17. Why anyone would want to do this, I couldn’t tell you.
Still feeling a slight bit of regex fever, I based my second task solution around a very simple /1/g
regex for counting the 1s in the binary representation of a number. Here’s the full solution:
use List::Util qw< sum >;
sub sum_idx_bit_set {
my $k = pop;
sum map { $_[$_] } grep { $k == ( ()= sprintf('%b',$_) =~ /1/g ) } 0..$#_
}
The whole thing is a grep
over all of the indices for any where the binary representation contains $k
ones. Those indices are fed into a simple map
to get the list element, and the whole thing is sum()
med up.
Raku
The Raku solution is conceptually similar, but there are a few language differences:
sub sum_idx_bit_set($k, @n) {
@n[ @n.keys.grep({ (TR:d/10/1/ with .base(2)) == $k }) ].sum
}
I decided to use TR//
here, which I could have also done with Perl. Converting to binary is easier in Raku thanks to the base()
method. The grep({...})
over the indices of @n
sets us up to take a slice of @n
and sum()
it up.
This solution feels a bit less Raku-ish to me, although my Raku is very rusty at the moment, not having looked at Raku code for nearly two years. Time to get hacking, eh!