Peter’s blog ✴ Week 225 ✴ 10 July 2023

THE WEEKLY CHALLENGE
Counting words and subtracting numbers

The Perl Camel

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)

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

Note: I have altered the above to match the examples. The original has 5 elements in @ints and only 4 in @left_right_sum_diff.

Examples


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)

Analysis

The task description is more-or-less a prose version of the required code:

  • Make a reversed copy of the input, @stni
  • For both @ints and @stni:
    • add (unshift) a zero at the beginning and remove (pop) the last element.
    • Add element $j to element $j + 1, from $j == 1 to the end
  • Reverse @stni again.

@ints and @stni are now respectively the @left and @right arrays, and @lrsd (as I have abbreviated it) is the element-by-element absolute difference between these.

Perl Weekly’s review

from Perl Weekly issue 625

Use of clever regex is in play. Perl is unbeatable when it comes to regex. Thanks for sharing the knowledge.

Try it 

Example: 1, 2, 3, 4, 5

Script


#!/usr/bin/perl

use v5.16;    # The Weekly Challenge - 2023-07-10
use utf8;     # Week 225 task 2 - Left right sum diff
use strict;   # Peter Campbell Smith
use warnings; # Blog: http://ccgi.campbellsmiths.force9.co.uk/challenge

left_right_sum_diff(10, 4, 8, 3);
left_right_sum_diff(1);
left_right_sum_diff(1, 2, 3, 4, 5);
left_right_sum_diff(3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5);

sub left_right_sum_diff {
    
    my (@ints, @stni, @lrsd, $count, $x);
    
    # initialise
    @ints = @_;
    $count = @ints - 1;
    
    # do the sums on @ints and the reverse of @ints
    @stni = reverse @ints;
    for $x (\@ints, \@stni) {
        unshift @$x, 0;
        pop @$x;
        $x->[$_] += $x->[$_ - 1] for 1 .. $count;
    }
    @stni = reverse @stni;
    
    # do the differences
    $lrsd[$_] = abs($ints[$_] - $stni[$_]) for 0 .. $count;
    
    # and spout
    say qq[\nInput:  \@ints  = (] . join(', ', @_) . q[)] .
        qq[\nOutput: \@left  = (] . join(', ', @ints) . q[)] .
        qq[\n        \@right = (] . join(', ', @stni) . q[)] .
        qq[\n        \@lrsd  = (] . join(', ', @lrsd) . q[)];
    
}

15 lines of code

Output from script


Input:  @ints  = (10, 4, 8, 3)
Output: @left  = (0, 10, 14, 22)
        @right = (15, 11, 3, 0)
        @lrsd  = (15, 1, 11, 22)

Input:  @ints  = (1)
Output: @left  = (0)
        @right = (0)
        @lrsd  = (0)

Input:  @ints  = (1, 2, 3, 4, 5)
Output: @left  = (0, 1, 3, 6, 10)
        @right = (14, 12, 9, 5, 0)
        @lrsd  = (14, 11, 6, 1, 10)

Input:  @ints  = (3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5)
Output: @left  = (0, 3, 4, 8, 9, 14, 23, 25, 31, 36, 39)
        @right = (41, 40, 36, 35, 30, 21, 19, 13, 8, 5, 0)
        @lrsd  = (41, 37, 32, 27, 21, 7, 4, 12, 23, 31, 39)

 

Any content of this website which has been created by Peter Campbell Smith is in the public domain