Perl Weekly Challenge: Week 172

Challenge 1:

Prime Partition

You are given two positive integers, $m and $n.

Write a script to find out the Prime Partition of the given number. No duplicates allowed.

For example,

Input: $m = 18, $n = 2
Output: 5, 13 or 7, 11

Input: $m = 19, $n = 3
Output: 3, 5, 11

Another relatively easy week.

my @primes = (1 .. $m).grep({ .is-prime });
my $count = 0;

I started the Raku version of my solution for task 1 with a list of all the prime numbers less than $m. I also set up a variable to hold the number of prime partitions found for reasons I shall explain in a bit.

for @primes.combinations($n) -> @combo {

Now we have a list of primes, .combinations() gives us a list of all the combinations of those primes with a length equal to $n.

    if ([+] @combo) == $m {
        @combo.join(q{, }).say;
        $count++;
    }

If the sum (found with [+]) of the elements of a combination equal $m, it is a prime partition. We print it out and increase $count by 1.

}

unless $count {
    say "No such prime partition.";
}

(Full code on Github.)

The spec didn't say what to do if $m doesn't have any prime partitions of length $n which is a distinct possibility so I added this last bit. If after examining all combinations, the value of $count is still 0, we print an error message.

Below is the Perl version. Once I had provided the combinations(), isPrime(), and sum() functions which I had written for previous challenges, the script worked the same as the Raku version.

my @primes = grep { isPrime($_) } 1 .. $m;
my $count = 0;

for my $combo (combinations(\@primes, $n)) {
    if (sum($combo) == $m) {
        say join q{, }, @{$combo};
        $count++;
    }
}

unless ($count) {
    say "No such prime partition.";
}

(Full code on Github.)

Challenge 2:

Five-number Summary

You are given an array of integers.

Write a script to compute the five-number summary of the given set of integers.

You can find the definition and example in the wikipedia page.

my @nums = @args.sort;
my $e = @nums.elems;

The referenced Wikipedia page suggest sorting the array of integers into ascending order before starting but because arguments in Raku are immutable, I copied the sorted list into a new list called @nums. I also stored the length of the list as we will be using that value a lot.

say "minimum:        ", @nums.min;

The minimum value of a list is easy to find with the .min() method.

say "lower quartile: ", $e %% 2 ?? (@nums[$e / 4 - 1] + @nums[$e / 4]) / 2 !! @nums[$e / 4];
say "median:         ", $e %% 2 ?? (@nums[$e / 2 - 1] + @nums[$e / 2]) / 2 !! @nums[$e / 2];
say "upper quartile: ", $e %% 2 ?? (@nums[$e / 4 * 3 - 1] + @nums[$e / 4 * 3]) / 2 !! @nums[$e / 4 * 3];

For the next three values, we only need to find the elements at 25%, 50% and 75% of the @nums list. Hover if the list has an even number will fall between two elements so we find those, add them together and divide by 2 to get the correct answer.

say "maximum:        ", @nums.max;

To find the maximum value of a list you merely have to use the .max() method.

(Full Raku code on Github.)

Barring syntactic differences, the Perl version is almost exactly the same.

my @nums = sort { $a <=> $b } @ARGV;
my $e = scalar @nums;

say "minimum:        ", $nums[0];

One exception is that Perl has no .min() method. However because @nums is sorted in ascending order, the first element (i.e. $nums[0]) will always be the minimum value.

say "lower quartile: ", $e % 2 == 0 ? ($nums[$e / 4 - 1] + $nums[$e / 4]) / 2 : $nums[$e / 4];
say "median:         ", $e % 2 == 0 ? ($nums[$e / 2 - 1] + $nums[$e / 2]) / 2 : $nums[$e / 2];
say "upper quartile: ", $e % 2 == 0 ? ($nums[$e / 4 * 3 - 1] + $nums[$e / 4 * 3]) / 2 : $nums[$e / 4 * 3];
say "maximum:        ", $nums[-1];

(Full Perl code on Github.)

Similiarly Perl has no .max() method but we know the last element (i.e. $nums[-1]) will always be the maximum value.