Advent Calendar - December 16, 2022

Friday, Dec 16, 2022| Tags: Perl, Raku

Advent Calendar 2022

|   Day 15   |   Day 16   |   Day 17   |


The gift is presented by Jaldhar H. Vyas. Today he is talking about his solution to “The Weekly Challenge - 188”. This is re-produced for Advent Calendar 2022 from the original post by him.



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;

(Full code on Github.)


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);

(Full code on Github.)


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;
}

(Full code on Github.)


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;

(Full code on Github.)



If you have any suggestion then please do share with us perlweeklychallenge@yahoo.com.

|   Advent Calendar 2022   |

SO WHAT DO YOU THINK ?

If you have any suggestions or ideas then please do share with us.

Contact with me