Perl Weekly Challenge: Week 306

Challenge 1:

Odd Sum

You are given an array of positive integers, @ints.

Write a script to return the sum of all possible odd-length subarrays of the given array. A subarray is a contiguous subsequence of the array.

Example 1
Input: @ints = (2, 5, 3, 6, 4)
Output: 77

Odd length sub-arrays:
(2) => 2
(5) => 5
(3) => 3
(6) => 6
(4) => 4
(2, 5, 3) => 10
(5, 3, 6) => 14
(3, 6, 4) => 13
(2, 5, 3, 6, 4) => 20

Sum => 2 + 5 + 3 + 6 + 4 + 10 + 14 + 13 + 20 => 77
Example 2
Input: @ints = (1, 3)
Output: 4

This is my Raku solution. As usual, input is taken from the command-line arguments.

First I declared a variable to hold the sum.

my $sum;

Amongst the many operators Raku provides, one of the most powerful is the ... or sequence operator. Given the first couple of terms, it can try and find the arithmetic or geometric sequence they represent and build a list that potentially continues to infinity. For example, in the line below, the terms before the sequence operator are 1 and 3. From this, Raku is able to deduce we want a list of odd numbers. In this case we only generate odd numbers up to @ints.elems i.e. the length of @ints. So cool!

for 1, 3 ... @ints.elems -> $i {

The outer loop gives the length of the subarrays we want to find, $i and the inner loop goes through @ints...

    for 0 .. @ints.elems - $i -> $j {

...and for each subarray of the required length, it sums it with .sum() and adds the result to $sum.

        $sum += @ints[$j ..^ $j + $i].sum;
    }
}

Finally we print $sum.

say $sum;

(Full code on Github.)

For Perl...

my $sum;

...we have to go through 1 to the length of @ints...

for my $i (1 .. scalar @ints) {

...and find the odd numbers for odd-length subarrays ourselves.

    if ($i % 2 == 1) {
        for my $j (0 .. scalar @ints - $i) {

We also have to provide our own sum() function.

            $sum += sum(@ints[$j .. $j + $i - 1]);
        }
    }
}

say $sum;

(Full code on Github.)

Challenge 2:

Last Element

You are given a array of integers, @ints.

Write a script to play a game where you pick two biggest integers in the given array, say x and y. Then do the following:

a) if x == y then remove both from the given array
b) if x != y then remove x and replace y with (y - x)

At the end of the game, there is at most one element left.

Return the last element if found otherwise return 0.

Example 1
Input: @ints = (3, 8, 5, 2, 9, 2)
Output: 1

Step 1: pick 8 and 9 => (3, 5, 2, 1, 2)
Step 2: pick 3 and 5 => (2, 2, 1, 2)
Step 3: pick 2 and 1 => (1, 2, 2)
Step 4: pick 2 and 1 => (1, 2)
Step 5: pick 1 and 2 => (1)
Example 2
Input: @ints = (3, 2, 5)
Output: 0

Step 1: pick 3 and 5 => (2, 2)
Step 2: pick 2 and 2 => ()

Input is taken from the command-line arguments.

my @ints = @args;

While we have atleast 2 elements left in @ints...

while @ints.elems > 1 {

...@ints is sorted in descending numeric order.

    @ints = @ints.sort({ $^b <=> $^a });

The first two elements which are the two largest numbers, are assigned to $y and $x respectively.

    my $y = @ints[0];
    my $x = @ints[1];

Now we follow the rules of the game as given in the spec.

If $x == $y both are removed from the list with .splice().

    if $x == $y {
        @ints.splice(0, 2);

If not, $x is removed and the value of $y is replaced by the value of $y - $x.

    } else {
        @ints.splice(1, 1);
        @ints[0] = $y - $x;
    }
}

This continues until we are down to 1 or 0 elements in `@ints. If 1, we print it otherwise we print 0.

say @ints[0] // 0;

(Full code on Github.)

For once no additional code has to be provided for the Perl version; it is just a streaightforward translation from Raku.

my @ints = @ARGV;

while (scalar @ints > 1) {
    @ints = sort { $b <=> $a } @ints;

    my $y = $ints[0];
    my $x = $ints[1];

    if ($x == $y) {
        splice @ints, 0, 2;
    } else {
        splice @ints, 1, 1;
        $ints[0] = $y - $x;
    }
}

say $ints[0] // 0;

(Full code on Github.)