My title is, again, word salad from the tasks, and have no musical connection. I feel like I’m losing my touch. But even so, let’s dive into Perl Weekly Challenge 258!
Task 1: Count Even Digits Number
You are given a array of positive integers, @ints
.
Write a script to find out how many integers have even number of digits.
Example 1
Input: @ints = (10, 1, 111, 24, 1000)
Output: 3
There are 3 integers having even digits i.e. 10, 24 and 1000.
Example 2
Input: @ints = (111, 1, 11111)
Output: 0
Example 3
Input: @ints = (2, 8, 1024, 256)
Output: 1
Approach
I could to an iterative approach where I divide each integer by 10 repeatedly until the result is less than 1 to count the digits it has, but this time, I already know the clever way to find out how many digits there are in a number without a loop: the integer portion of log10(n) + 1
.
Raku
sub evenDigitCount(@ints) {
my $count = 0; # in case there are no even digit ints
for @ints -> $n {
$count++ if floor(log10($n) + 1) % 2 == 0;
}
return $count;
}
View the entire Raku script for this task on GitHub.
Perl
The only thing that complicates the Perl solution is that Perl doesn’t have built-in log10()
or floor()
functions, but we can easily import them from the standard POSIX module.
use POSIX qw( log10 floor );
sub evenDigitCount(@ints) {
my $count = 0; # in case there are no even digit ints
foreach my $n ( @ints ) {
$count++ if floor(log10($n) + 1) % 2 == 0;
}
return $count;
}
View the entire Perl script for this task on GitHub.
Python
For once, Python is a little more like Perl than it is Raku: we have to import floor()
and log10()
from the math module. Again, I get to use the one-line if statement syntax I learned last week.
from math import floor, log10
def evenDigitCount(ints):
count = 0; # in case there are no even digit ints
for n in ints:
if floor(log10(n) + 1) % 2 == 0: count += 1
return count
View the entire Python script for this task on GitHub.
Task 2: Sum of Values
You are given an array of integers, @ints
and an integer $k
.
Write a script to find the sum of values whose index binary representation has exactly $k
number of 1-bit
set.
Example 1
Input: @ints = (2, 5, 9, 11, 3), $k = 1
Output: 17
Binary representation of index 0 = 0
Binary representation of index 1 = 1
Binary representation of index 2 = 10
Binary representation of index 3 = 11
Binary representation of index 4 = 100
So the indices 1, 2 and 4 have total one 1-bit sets.
Therefore the sum, $ints[1] + $ints[2] + $ints[4] = 17
Example 2
Input: @ints = (2, 5, 9, 11, 3), $k = 2
Output: 11
Example 3
Input: @ints = (2, 5, 9, 11, 3), $k = 0
Output: 2
Approach
This time I don’t have a clever approach, so I’m going to count the set bits in the number by looping through them. However, we’re going to be using this multiple times for the same number, so it makes sense to cache the results so we only wind up counting the set bits once per number.
Raku
In Raku, there’s an is cached
trait that can be added to a routine:
Causes the return value of a routine to be stored, so that when subsequent calls with the same list of arguments are made, the stored value can be returned immediately instead of re-running the routine.
use experimental :cached;
sub setBitCount($i) is cached {
my $count = 0;
my $bit = 1;
while ($bit <= $i) {
$count++ if $i +& $bit; # count if we have this bit set
$bit +<= 1; # shift bits left, ie 10 becomes 100
}
return $count;
}
sub valueSum($k, @ints) {
my $sum = 0;
for 0 .. @ints.end -> $i {
$sum += @ints[$i] if setBitCount($i) == $k;
}
return $sum;
}
View the entire Raku script for this task on GitHub.
Perl
In Perl, we do this by using the built-in Memoize module:
use Memoize;
memoize('setBitCount');
sub setBitCount($i) {
my $count = 0;
my $bit = 1;
while ($bit <= $i) {
$count++ if $i & $bit; # count if we have this bit set
$bit <<= 1; # shift bits left, ie 10 becomes 100
}
return $count;
}
sub valueSum($k, @ints) {
my $sum = 0;
foreach my $i ( 0 .. $#ints ) {
$sum += $ints[$i] if setBitCount($i) == $k;
}
return $sum;
}
View the entire Perl script for this task on GitHub.
Python
In Python, we accomplish this using the @cache
decorator in functools:
from functools import cache
@cache
def setBitCount(i):
count = 0
bit = 1
while (bit <= i):
if i & bit: count += 1 # count if we have this bit set
bit <<= 1 # shift bits left, ie 10 becomes 100
return count
def valueSum(k, ints):
sum = 0
for i in range(len(ints)):
if setBitCount(i) == k: sum += ints[i]
return sum
View the entire Python script for this task on GitHub.
Here’s all my solutions in GItHub: https://github.com/packy/perlweeklychallenge-club/tree/master/challenge-258/packy-anderson