Perl Weekly Challenge: Week 241
No one-liners this week but the challenges were pretty easy to solve anyway.
Challenge 1:
Arithmetic Triplets
You are given an array (3 or more members) of integers in increasing order and a positive integer.
Write a script to find out the number of unique Arithmetic Triplets satisfying the following rules:
a) i < j < k
b) nums[j] - nums[i] == diff
c) nums[k] - nums[j] == diff
Example 1
Input: @nums = (0, 1, 4, 6, 7, 10)
$diff = 3
Output: 2
Index (1, 2, 4) is an arithmetic triplet because both 7 - 4 == 3 and 4 - 1 == 3.
Index (2, 4, 5) is an arithmetic triplet because both 10 - 7 == 3 and 7 - 4 == 3.
Example 2
Input: @nums = (4, 5, 6, 7, 8, 9)
$diff = 2
Output: 2
(0, 2, 4) is an arithmetic triplet because both 8 - 6 == 2 and 6 - 4 == 2.
(1, 3, 5) is an arithmetic triplet because both 9 - 7 == 2 and 7 - 5 == 2.
There have been lots of problems involving triplets in previous challenges. While I couldn't directly cut and paste code from them into this weeks problems, at least I had a good idea about how to go about solving it.
My script assumes that $diff
is the first command-line argument and the rest of the arguments make up @nums
.
Then for @nums
...
@nums
We find all the triplets which is easy to do with the .combinations()
method.
.combinations(3)
Then we search through the list of combinations to find arithmetic triplets using .grep()
.
.grep({
The criteria from the spec can be coded almost verbatim.
my ($i, $j, $k) = @$_;
$i < $j &&
$j < $k &&
$j - $i == $diff &&
$k - $j == $diff;
})
We don't actually need to know what the arithmetic triplets are just how many
so we can count them with .elems()
...
.elems
...and print the results with .say()
.
.say;
For Perl I had to provide my own combinations()
which I already had from previous
challenges. With that, it works the same way as in Raku.
say scalar grep {
my ($i, $j, $k) = @{$_};
$i < $j &&
$j < $k &&
$j - $i == $diff &&
$k - $j == $diff;
} combinations(\@nums, 3);
Challenge 2:
Prime Order
You are given an array of unique positive integers greater than 2.
Write a script to sort them in ascending order of the count of their prime factors, tie-breaking by ascending value.
Example 1
Input: @int = (11, 8, 27, 4)
Output: (11, 4, 8, 27)
Prime factors of 11 => 11
Prime factors of 4 => 2, 2
Prime factors of 8 => 2, 2, 2
Prime factors of 27 => 3, 3, 3
Prime factors have also come up several times in previous challenges. For both Raku and Perl, I used the factorize()
function I wrote for week 168 challenge 2
Now when passing a comparison block to .sort()
, instead of directly comparing the
elements, we call factorize()
on each one count the prime factors with .elems
and use that as the basis of comparison. And that's it! The rest of the code
is just to print the results in a similar manner to the example output.
say q{(},
@int.sort({ factorize($^a).elems <=> factorize($^b).elems }).join(q{, }),
q{)};
The Perl solution works the same as in Raku except Perls' version of factorize()
also required the provision of an isPrime()
function.
say q{(},
(join q{, }, sort { scalar factorize($a) <=> scalar factorize($b) } @ARGV),
q{)};
One thing that later occurred to me is that because sort()
compares elements
two by two, every element in @int
except the first and last are going to have
their prime factors calculated twice which for long lists or large numbers could
be very inefficient. So for those cases it would pay to memoize factorize()
. But for this example it doesn't matter.