Perl Weekly Challenge: Week 188
Challenge 1:
Divisible Pairs
You are given list of integers
@list
of size$n
and divisor$k
.Write a script to find out count of pairs in the given list that satisfies the following rules.
The pair (i, j) is eligible if and only if
a) 0 <= i < j < len(list)
b) list[i] + list[j] is divisible by k
Example 1
Input: @list = (4, 5, 1, 6), $k = 2
Output: 2
Example 2
Input: @list = (1, 2, 3, 4), $k = 2
Output: 2
Example 3
Input: @list = (1, 3, 4, 5), $k = 3
Output: 2
Example 4
Input: @list = (5, 1, 2, 3), $k = 4
Output: 2
Example 5
Input: @list = (7, 2, 4, 5), $k = 4
Output: 1
In Raku this problem can be solved as a one-liner but I've chosen to spread it out a bit for clarity.
I found the way condition a in the spec is described to be a little unclear; what it
actually means is that the values of i
and j
range between 0 and the size of the list.
(0 ..^ @list.elems)
For that range, we get a list of all the pairs of values with .combinations()
...
.combinations(2)
...We .grep()
through that list to find all the pairs where their .sum()
is evenly
divisible by $k
...
.grep({ @$_.sum %% $k})
...Then we count how many pairs we found... .elems
...and print that out.
.say;
The Perl solution is not quite so concise. For one thing, I had to supply my own combinations()
function which
luckily I had from previous challenges. I also missed having the integer modulus operator %%
and the .sum()
method.
say scalar grep { ($list[$_->[0]] + $list[$_->[1]]) % $k == 0; }
combinations([0 .. scalar @list - 1], 2);
Challenge 2:
Total Zero
You are given two positive integers
$x
and$y
.Write a script to find out the number of operations needed to make both
ZERO
. Each operation is made up either of the followings:
$x = $x - $y if $x >= $y
or
$y = $y - $x if $y >= $x (using the original value of $x)
Example 1
Input: $x = 5, $y = 4
Output: 5
Example 2
Input: $x = 4, $y = 6
Output: 3
Example 3
Input: $x = 2, $y = 5
Output: 4
Example 4
Input: $x = 3, $y = 1
Output: 3
Example 5
Input: $x = 7, $y = 4
Output: 5
Normally function parameters in Raku are immutable. To be able to change them,
you have to add the is copy
trait.
sub MAIN(
Int $x is copy, #= a positive integer
Int $y is copy #= a positive integer
) {
I defined a counter for the number of operations.
my $operations = 0;
Then I kept on applying the operations given in the spec until both $x
and $y
were 0.
repeat {
In order to perform operation 2 correctly, I had to cache the value of $x
before operation 1
was applied.
my $prevX = $x;
if $x >= $y {
$x -= $y;
}
if $y >= $prevX {
$y -= $prevX;
}
The spec is misleading IMHO. Originally, I incremented $operations
within each if
block.
But for the example inputs, this gave me a result 1 greater than the expected output. What we
really want is not the total number of operations as I assumed, but the number of times we go
through the loop.
$operations++;
} until $x == 0 && $y == 0;
Finally, we can print the result.
say $operations;
}
This is the Perl version. No concerns about immutablity and we use do ... while
instead of
repeat ... until
in the loop.
my ($x, $y) = @ARGV;
my $operations = 0;
do {
my $prevX = $x;
if ($x >= $y) {
$x -= $y;
}
if ($y >= $prevX) {
$y -= $prevX;
}
$operations++;
} while ($x != 0 && $y != 0);
say $operations;