This is my response to The Weekly Challenge #172.
$m
and $n
.
Prime Partition
of the given number.
No duplicates allowed.
Input: $m = 18, $n = 2
Output: 5, 13 or 7, 11
Input: $m = 19, $n = 3
Output: 3, 5, 11
$m
is the number to partition,
and $n
is the number of primes we want in the partition. See e.g.
mathworld.wolfram.com/PrimePartition.html
for a detailed explanation.
#! /usr/bin/env raku
unit sub MAIN (Int $m where $m > 0, Int $n where $n > 0, :a($all)); # [1]
my $primes := (2 .. $m).grep( *.is-prime ); # [2]
for $primes.combinations($n) -> @combination # [3]
{
my $sum = @combination.sum; # [4]
if $sum == $m # [5]
{
say @combination.join(", "); # [6]
last unless $all; # [7]
}
}
[1] Specify the two values. Also note the «-all», which will be discussed in [7].
[2] Get the primes, up to (and including, even if that is excessive) the original
number. (But this will give us the number itself, if we go for $n = 1
.)
[3] Then we use combinations($n)
to get all
the possible combinations of values in the original list - of size $n
,
and iterate over them.
See
docs.raku.org/routine/combinations
for more information about combinations
.
[4] Get the sum of all the values.
[5] Do we have a match?
[6] If so, print the primes.
[7] And we are done, unless we want the program to print all the matches.
Running it:
$ ./prime-partition 18 2
5, 13
$ ./prime-partition 19 3
3, 5, 11
Use the «-a» command line option to get all the answers, and not just the first one («first» as in the first chosen by the program):
$ ./prime-partition -a 18 2
5, 13
7, 11
Looking good.
We can try with a prime, which cannot be partitioned:
$ ./prime-partition 19 4
$ ./prime-partition -a 19 4
Unless you consider a partition of 1 to be a partition:
$ ./prime-partition 19 1
19
five-number summary
of the given set of
integers.
You can find the definition and example in the wikipedia page.
#! /usr/bin/env raku
unit sub MAIN (*@integers where all(@integers) ~~ Int, :v($verbose)); # [1]
my @sorted = @integers>>.Int.sort; # [2]
say ": Sorted: @sorted[]" if $verbose;
my @fns = # [3]
(
@sorted[0], # [4]
lower_quartile(@sorted), # [6]
median(@sorted), # [5]
upper_quartile(@sorted), # [7]
@sorted[*-1] # [8]
);
sub median (@values) # [5a]
{
my $count = @values.elems;
return @values[$count/2] if $count % 2; # [5b]
return (@values[$count/2 -0.5] + @values[$count/2 +0.5]) / 2; # [5c]
}
sub lower_quartile (@values) # [6a]
{
my $count = @values.elems;
return median(@values[0 .. $count/2 -0.5]);
}
sub upper_quartile (@values) # [7a]
{
my $count = @values.elems;
return median(@values[$count/2 .. *]);
}
say @fns.join(", "); # [9]
[1]
A slurpy argument (*@
) to get all the values in
one array, combined with an all
junction to ensure that they are
all integers.
See docs.raku.org/type/Signature#index-entry-slurpy_argument for more information about slurpy arguments.
See
docs.raku.org/routine/all
for more information about the all
Junction.
[2] Sort the values, after coercing them to integers (with
>>.Int
) as they are strings (or IntStr
rather)
when received as input from the command line. Sorting numbers as strings
is not a good idea:
> say <1 2 11 12>.sort; # -> (1 2 11 12)
> say "1 2 11 12".words.sort; # -> (1 11 12 2)
[3] Collect the 5 values
[4] The first value is the one with the lowest value in the array, which is the first one - as the array is sorted.
[5] The third one (yes, I have skipped the second one - as this one should be explained first) is the median. This is the value in the middle of the array. In the case of an odd number of elements, it is the middle value itself [5b]. If we have an even number of elements, we take the average of the two middle values [5c].
[6] There are many ways of computing the lower quartile, according to en.wikipedia.org/wiki/Quartile. I have chosen the one called «method 2», where we compute the median of the first half of the values. In the case of an odd number of elements, the middle one is included.
[7] The upper quartile is the identical to [6a], but we use the second half of the values. The middle value is included here as well, if we have an odd number of elements.
[8] The fifth value is the one with the highest value in the array, which is the last one - as the array is sorted.
[9] Print the 5 values.
Running it:
$ ./five-number-summary 0 0 1 2 63 61 27 13
0, 0.5, 7.5, 44, 63
We got the same result as the wikipedia page.
And that's it.