PWC 258 › Counting Digits and Summing Values

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:

Index [base10]Index [base2]Value
002
115
2109
31111
41003
@ints with index (decimal and binary)

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!

Leave a Reply

Your email address will not be published. Required fields are marked *