Advent Calendar - December 22, 2023

Friday, Dec 22, 2023| Tags: Perl

Advent Calendar 2023

|   Day 21   |   Day 22   |   Day 23   |


The gift is presented by Augie De Blieck Jr.. Today he is talking about his solution to The Weekly Challenge - 238. This is re-produced for Advent Calendar 2023 from the original post.



The Weekly Challenge began as a Perl-focused exercise but has since expanded to let any and all languages in. It’s still mostly Perl, but I’ll be using it as an avenue to explore other languages, as well.


Running Sum


This week’s challenge is to write a script that takes an array and outputs an array where each value is a sum of the numbers before it.

For example:

Input: (1, 2, 3, 4, 5)
Output: (1, 3, 6, 10, 15)

This one is fairly straightforward. You can loop right over it and add the numbers as you go pretty quickly:


use Data::Dumper qw/Dumper/;

my @array = (1, 2, 3, 4, 5);
my $sum = 0;
my @sum_array = map{ $sum += $_; } @array;

print Dumper \@sum_array;

That’s pretty simple, I think. I also have a "use strict" and "use warnings" bit at the top, but didn’t think it was necessary for this presentation.

The variable names are pretty direct, also. In a real world scenario, I wouldn’t name an array @array, but in a challenge like this, it’s fine.

I love using Data::Dumper to easily print out all kinds of variables in Perl, but especially hashes of hashes and arrays of hashes and all that second level kind of craziness.

I spent just enough time learning functional programming to take any excuse to use map{} or grep{} in Perl. In my first version of this script, I was updating @sum_array inside the map statement. Then I realized how silly that was. If you’re mapping over something, the map command will produce a new array — just capture that!

There is some advice out there about not using map in place of a for or foreach loop. It’s meant as a data filter. I don’t always follow that advice, but I try to. That’s what I did here.

Two related hills I’ll die on: Don’t take the increment/decrement counter away from me, and let me have “+=” and “*=” and all the rest. It always throws me off when a language doesn’t have that.


Refactor for Prettiness


Having solved the issue, I took the challenge literally. Data::Dumper doesn’t print out an array like this:


(1, 3, 6, 10, 15)

It shows it like this:


$VAR1 = [
      1,
      3,
      6,
      10,
      15
    ];

So I had to create a prettier printer. While I’m sure there are a hundred good Perl modules I could download from CPAN to do it, I wanted to code something myself for this challenge.

That’s how I ended up with this code at the end, including a bit of code to run all three examples from the challenge:


# Test Data:
my @test1 = (1, 2, 3, 4, 5);
my @test2 = (1, 1, 1, 1, 1);
my @test3 = (0, -1, 1, 2);
my @array_examples = (\@test1, \@test2, \@test3);


print "Running Sum Code Results:\n";
print "=========================\n\n";

foreach my $array_ref (@array_examples) {

    print "Array: " ;
    pretty_print_array( $array_ref );

    my @results = show_running_sum($array_ref);

    print "Results: ";
    pretty_print_array(\@results);

    print "\n";

}

##
## Subroutines
##

sub show_running_sum {

    ## Ultimately, this is the heart of the solution

    my @array = @{ shift() };
    my $sum = 0;

    return map{ $sum += $_ } @array;

}

sub pretty_print_array {

    ## Total overkill, but I'm new and over-enthusiastic.
    ## In reality, I'd find something on CPAN for this.


    my @array = @{ shift() };
    my $length = scalar @array;
    my $count = 1;

    print "(";

    foreach my $value(@array) {
        print $value;
        print ", " if $count < $length;
        $count++;
    }

    print ")\n";

    return;
}

Turns out, making the final output look prettier took more coding than the challenge, itself. Such is life sometimes…

I’m also sure there are shorter, less readable ways to do it. I’ll take this way. I’ll take readability over Perl Golf, though I do enjoy those efforts.

Putting everything in new neat subroutines makes testing easier, also, though I didn’t test for this example. I’m sure I’ll do some TDD in a future weekly challenge, though.

You can find the full script on my Github.

I also solved this challenge in Elixir, in case you are functionally-curious.


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

|   Advent Calendar 2023   |

SO WHAT DO YOU THINK ?

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

Contact with me