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.

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.