Perl Weekly Challenge 225: Left Right Sum Diff

These are some answers to the Week 225, Task 2, of the Perl Weekly Challenge organized by Mohammad S. Anwar.

Spoiler Alert: This weekly challenge deadline is due in a few days from now (on July 16, 2023 at 23:59). This blog post offers some solutions to this challenge. Please don’t read on if you intend to complete the challenge on your own.

Task 2: Left Right Sum Diff

You are given an array of integers, @ints.

Write a script to return left right sum diff array as shown below:

@ints = (a, b, c, d, e)

@left  = (0, a, (a+b), (a+b+c))
@right = ((c+d+e), (d+e), e, 0)
@left_right_sum_diff = ( | 0 - (c+d+e) |,
                         | a - (d+e)   |,
                         | (a+b) - e   |,
                         | (a+b+c) - 0 | )

Example 1:

Input: @ints = (10, 4, 8, 3)
Output: (15, 1, 11, 22)

@left  = (0, 10, 14, 22)
@right = (15, 11, 3, 0)

@left_right_sum_diff = ( |0-15|, |10-11|, |14-3|, |22-0|)
                     = (15, 1, 11, 22)

Example 2:

Input: @ints = (1)
Output: (0)

@left  = (0)
@right = (0)

@left_right_sum_diff = ( |0-0| ) = (0)

Example 3:

Input: @ints = (1, 2, 3, 4, 5)
Output: (14, 11, 6, 1, 10)

@left  = (0, 1, 3, 6, 10)
@right = (14, 12, 9, 5, 0)

@left_right_sum_diff = ( |0-14|, |1-12|, |3-9|, |6-5|, |10-0|)
                     = (14, 11, 6, 1, 10)

Frankly, I don't understand the logic of this task, nor its aim. So I'll simply mimic blindly the task description and examples. The unstated assumption derived from the examples is that the left and right arrays should have the same size as the input array, that the left array should have a zero followed by partial sums of the input array except the last one, and that the right array should also have partial sums of the input array in reverse order, except the first one, and followed by a zero.

Left Right Sum Diff in Raku

In Raku, we can use reduction operator [] together with the + operator (to sum the items), prefixed with a \ to obtain partial or intermediate sums:

say [\+] 1..5;    # prints: (1 3 6 10 15)

This is sometimes called a triangular reduction. We use it for computing both the left and the right arrays. The rest of the program is straight forward: we use a map to perform the subtractions.

sub lrsd (@in) {
    my @l = (0, [\+] @in[0..@in.end - 1]).flat;
    my @r = 
    (( [\+] @in.reverse[0..@in.end - 1]).reverse, 0).flat;
    return map { (@l[$_] - @r[$_]).abs }, 0..@l.end;
}
my @tests = (10, 4, 8, 3), (1,), (1, 2, 3, 4, 5);
for @tests -> @test {
    printf "%-10s => ", "@test[]";
    say lrsd @test;
}

This program displays the following output:

$ raku ./left-right-sum-diff.raku
10 4 8 3   => (15 1 11 22)
1          => (0)
1 2 3 4 5  => (14 11 6 1 10)

Left Right Sum Diff in Perl

Perl doesn't have the reduction operator, but it is not complicated to compute partial sums in a for loop.

use strict;
use warnings;
use feature 'say';

sub lrsd  {
    my @in = @_;
    my @l = (0);
    push @l, $l[-1] + $in[$_] for 0..$#in-1;
    my @r = (0); 
    push @r, $r[-1] + $in[$_] for reverse 1..$#in;
    @r = reverse @r;
    return join " ", map { abs ($l[$_] - $r[$_]) } 0..$#l;
}

my @tests = ([10, 4, 8, 3], [1,], [1, 2, 3, 4, 5] );
for my $test (@tests) {
    printf "%-10s => ", "@$test";
    say lrsd @$test;
}

This program displays the following output:

$ perl ./left-right-sum-diff.pl
10 4 8 3   => 15 1 11 22
1          => 0
1 2 3 4 5  => 14 11 6 1 10

Wrapping up

The next week Perl Weekly Challenge will start soon. If you want to participate in this challenge, please check https://perlweeklychallenge.org/ and make sure you answer the challenge before 23:59 BST (British summer time) on July 23, 2023. And, please, also spread the word about the Perl Weekly Challenge if you can.

Leave a comment

About laurent_r

user-pic I am the author of the "Think Perl 6" book (O'Reilly, 2017) and I blog about the Perl 5 and Raku programming languages.