Perl Weekly Challenge 172.

My solutions (task 1 and task 2 ) to the The Weekly Challenge - 172.

Task 1: Prime Partition

Submitted by: Mohammad S Anwar
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

I can use a recursive procedure that takes as arguments $m, $n and an array $p of primes, removing a prime from the array, substracting it from $m and decrementing $n until success ($m and $n reach zero) or failure. I may use Math::Primes::Util to generate the array. My first attempt is the following 4-liner

perl -MMath::Prime::Util=primes -E 'my ($m,$n)=@ARGV; my @p=@{primes($m)};
say "$m=". join "+", grep {$_>0} p($m,$n,\@p);sub p($m, $n, $a){
return $m==0?(0):() if $n==0; my @a=grep {$_<=$m} @$a; while(@a){
my $p=pop @a; my @r=p($m-$p, $n-1, \@a); return (@r, $p) if @r;} return ();}
' 19 3

Results:

19=3+5+11

It seems to work, but it returns at most one partition. Therefore, I modify the recursive function p($m, $n, $a) to return all partitions of $m into $n elements of the set $a.

perl -MMath::Prime::Util=primes -E 'my ($m,$n)=@ARGV; my @p=@{primes($m)};
say "$m=". join "+", @$_ foreach p($m, $n, \@p);sub p($m, $n, $a){return $m==0?
([]):() if $n==0; my @a=grep {$_<=$m} @$a; my @f=(); while(@a){my $p=pop @a;
my @r=p($m-$p, $n-1, \@a); push @f, map {push @$_, $p; $_} @r if @r;}return @f;}
' 50 5

Results:

50=2+3+5+11+29
50=2+3+5+17+23
50=2+5+7+13+23
50=2+5+7+17+19
50=2+5+11+13+19
50=2+7+11+13+17

So it seems to work.

The full code is

 1  # Perl weekly challenge 172
 2  # Task 1: Prime partition
 3  #
 4  # See https://wlmb.github.io/2022/07/04/PWC172/#task-1-prime-partition
 5  use v5.36;
 6  use Math::Prime::Util qw(primes);
 7  say("Usage: ./ch-1.pl M N\nto find the N-term prime partitions of M\n"), exit
 8      unless @ARGV==2;
 9  my ($m,$n)=@ARGV;
10  my @primes=@{primes($m)};
11  my @result= partitions($m,$n,\@primes);
12  say "$m=", join "+", @$_ foreach @result;
13  sub partitions($m, $n, $set){
14      # return all partitions of $m into $n elements of the ordered $set
15      return $m==0?([]):() if $n==0; # () means failure, ([]) means we are done
16      my @set=grep {$_<=$m} @$set; # remove high unneeded elements
17      my @results=();
18      while(@set){
19          my $element=pop @set; # try highest elements first
20          my @r=partitions($m-$element, $n-1, \@set);
21          push @results, map {push @$_, $element; $_} @r if @r;
22      }
23      return @results;
24  }

Example:

./ch-1.pl 50 5

Results:

50=2+3+5+11+29
50=2+3+5+17+23
50=2+5+7+13+23
50=2+5+7+17+19
50=2+5+11+13+19
50=2+7+11+13+17

Had I been more thoughtful, I could have guessed: I checked the documentation of Math::Prime::Util and there it was, ready for use, the function forpart, to produce partitions, yielding a true oneliner:

perl -MMath::Prime::Util=forpart -MList::Util=uniq -E '
($m, $n)=@ARGV; forpart {say "$m=", join "+",@_ if @_==uniq @_} $m, {n=>$n,prime=>1}' 50 5

Results:

50=2+3+5+11+29
50=2+3+5+17+23
50=2+5+7+13+23
50=2+5+7+17+19
50=2+5+11+13+19
50=2+7+11+13+17

I just had to remove partitions with duplicates. I can use this results to verify my programs above.

Task 2: Five-number summary

Submitted by: Mohammad S Anwar
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.

The five number summary of a set of numbers is given by its minimum, lower quartile, median, upper quartile and maximum. The lower and upper quartiles are the medians of the first half and second half of the ordered data. There are various conventions about the definition of the first and second halfs. The one I use here excludes the median from both sets. To calculate the median we have to distinguish between an even and an odd number of elements in the set. If the number is odd, the median is the element at the center of the ordered array. If the number is even, then an arithmetic average is taken among the two centermost data points. This yields a three-liner:

perl -E '@a=sort {$a<=>$b} @ARGV; ($l, $h)=($a[0], $a[-1]); $m=c(@a);
$f=c(@a[0..(@a-2)/2]); $t=c(@a[(@a+1)/2..@a-1]); say "$l\n $f\n $m\n$t\n $h";
sub c(@d){@d%2?$d[(@d-1)/2]:($d[@d/2-1]+$d[@d/2])/2}
' 0 0 1 2 63 61 27 13

Results:

 0
 0.5
 7.5
44
63

The full code is

 1  # Perl weekly challenge 172
 2  # Task 2: Five-number summary
 3  #
 4  # See https://wlmb.github.io/2022/07/04/PWC172/#task-1-five-number-summary
 5  use v5.36;
 6  say("Usage: ./ch-2.pl N1 N2...Nk\nto find the five-number summary of the sequence N1...Nk"), exit
 7      unless @ARGV;
 8  say("The sequence should have at least 2 elements"), exit unless @ARGV>=2;
 9  my @data=sort {$a<=>$b} @ARGV;
10  my ($min, $max)=($data[0], $data[-1]);
11  my $median=median(@data);
12  my $q1=median(@data[0..(@data-2)/2]);
13  my $q3=median(@data[(@data+1)/2..@data-1]);
14  say join " ", "The five-number summary of ", @ARGV, "is";
15  say "min=$min, Q1=$q1, median=$median, Q3=$q3, max=$max";
16
17  sub median(@d){
18      @d%2?$d[(@d-1)/2]:($d[@d/2-1]+$d[@d/2])/2
19  }

Example:

./ch-2.pl 0 0 1 2 63 61 27 13

Results:

The five-number summary of  0 0 1 2 63 61 27 13 is
min=0, Q1=0.5, median=7.5, Q3=44, max=63

Other examples:

for i in 1 2 3 4 5 6 7; do echo; ./ch-2.pl `seq $i`; done

Results:

The sequence should have at least 2 elements

The five-number summary of  1 2 is
min=1, Q1=1, median=1.5, Q3=2, max=2

The five-number summary of  1 2 3 is
min=1, Q1=1, median=2, Q3=3, max=3

The five-number summary of  1 2 3 4 is
min=1, Q1=1.5, median=2.5, Q3=3.5, max=4

The five-number summary of  1 2 3 4 5 is
min=1, Q1=1.5, median=3, Q3=4.5, max=5

The five-number summary of  1 2 3 4 5 6 is
min=1, Q1=2, median=3.5, Q3=5, max=6

The five-number summary of  1 2 3 4 5 6 7 is
min=1, Q1=2, median=4, Q3=6, max=7

The values for the first and third quartiles of these sequences might look suspicious, but for such small data sets, they strongly depend on the convention adopted.

Written on July 4, 2022