Perl Weekly Challenge 244: Group Hero

These are some answers to the Week 244, 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 November 26, 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: Group Hero

You are given an array of integers representing the strength.

Write a script to return the sum of the powers of all possible combinations; power is defined as the square of the largest number in a sequence, multiplied by the smallest.

Example 1

Input: @nums = (2, 1, 4)
Output: 141

Group 1: (2) => square(max(2)) * min(2) => 4 * 2 => 8
Group 2: (1) => square(max(1)) * min(1) => 1 * 1 => 1
Group 3: (4) => square(max(4)) * min(4) => 16 * 4 => 64
Group 4: (2,1) => square(max(2,1)) * min(2,1) => 4 * 1 => 4
Group 5: (2,4) => square(max(2,4)) * min(2,4) => 16 * 2 => 32
Group 6: (1,4) => square(max(1,4)) * min(1,4) => 16 * 1 => 16
Group 7: (2,1,4) => square(max(2,1,4)) * min(2,1,4) => 16 * 1 => 16

Sum: 8 + 1 + 64 + 4 + 32 + 16 + 16 => 141

Group Hero in Raku

This task is fairly straight forward in Raku, using the built-in combinations, max, and min methods. Note that we also use the built-in postfix ² operator to find the square of a number.

sub group-hero (@in) {
    my $sum = 0;
    for @in.combinations: 1..@in.elems -> @comb {
        $sum += @comb.max² * @comb.min;
    }
    return $sum;
}  

for <2 1 4>, <4 1 5 2> -> @test {
    printf "%-10s => ", "@test[]";
    say group-hero @test;
}

This program displays the following output:

$ raku ./group-hero.raku 7
2 1 4      => 141
4 1 5 2    => 566

Group Hero in Perl

Here, we cannot port simply the Raku program to Perl, because Perl lacks the combinations, max, and min functions. As I stated many times, I eschew using on-the-shelf modules in coding challenge, because using ready-made products is not the essence of a challenge (but I would of course do so in real life programming). We are looking for combinations, but are actually using only pairs of items for calculations. So, I decided to first sort the input array and hand-pick the first and last items of any combination.

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

sub group_hero {
    # Caution: this works only with input arrays of 3 items
    my @in = sort { $a <=> $b } @_;
    my $sum = 0;
    $sum += $_ * $_ * $_ for @in;
    my ($i, $j) = (0, 0);

    for $j (0..$#in) {
        for $i (1..$#in) {  #gap
            next unless defined $in[$j + $i];
            $sum += $in[$j] * $in[$j + $i] * $in[$j + $i];
        }
    }
    $sum += $in[0] * $in[$#in] * $in[$#in];
    return $sum;
}

for my $test ([<2 1 4>]) {
    printf "%-10s => ", "@$test";
    say group_hero @$test;
}

This works well with input arrays of three items:

$ perl ./group-hero.pl
2 1 4      => 141

but this wouldn't work with arrays having more than three elements. As I don't have time right now to solve this issue, I'll leave it at that, and may come back to it later if I find the time to suggest a better more generic solution. Three nested loops (instead of two) should probably do the trick, and it shouldn't be too difficult, but I can't do it today. Later this week if possible.

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 December 3, 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.