Raku Solutions Weekly Review
Getting in Touch
Email › Email me (Andrew) with any feedback about this review.
GitHub › Submit a pull request for any issues you may find with this page.
Twitter › Join the discussion on Twitter!
We’d greatly appreciate any feedback you’d like to give.
Welcome to the Raku Review for Week 082 of The Weekly Challenge!. For a quick overview, go through the original tasks and recap of the weekly challenge.
Task 1. Common Factors
In the first task, we had to find common factors of two integer numbers. The solutions submitted can be roughly classified into a few categories:
- With two greps
- By intersection of factors
- Employing the GCD
- With junctions
Using a row of grep
s
In this kind of solutions, the range of numbers is first filtered to take the numbers by which $A
is divisible, and then the second filter is applied to do the same for $B
. The remaining numbers are the numbers in question.
For example, in my solution, we see:
say ((1 .. ($a max $b)).grep: $a %% *).grep: $b %% *;
Intersection of lists of factors
Here, the first step is to find all the factors for each input number independently and then compute their intersection. Of course, using Raku’s operator (&)
for set intersection.
In the program by Arne Sommer:
my @M-factors = $include-self ?? (1..$M).grep({ $M %% $_ }) !! (1..$M/2).grep({ $M %% $_ });
my @N-factors = $include-self ?? (1..$N).grep({ $N %% $_ }) !! (1..$N/2).grep({ $N %% $_ });
my %common = @M-factors (&) @N-factors;
Or the same operator but spellt out as a Unicode symbol ∩
as Jaldhar H. Vyas did it:
sub MAIN(Int $M, Int $N) {
(factors($M) ∩ factors($N)).keys.sort.join(', ').say;
}
Simon Proctor demonstrates another example of this approach:
sub MAIN ( UInt $M, UInt $N ) {
say "({(fac($M) (&) fac($N)).keys.sort.join(', ')})"
}
sub fac( UInt $v ) {
(1..^$v).grep( $v %% * )
}
Notice how the whole line of Raku code is interpolated in curly braces inside a double-quoted string.
By the way, in a couple of solutions, finding the factors is optimised to take two factors at once if possible. Examine the take
parts of Colin Crain’s solution:
sub factor (Int $num) {
gather {
for (1..$num.sqrt.Int).grep({$num %% $_}) {
take $_;
take $num div $_;
}
}
}
With the help of GCD
GCD, or greatest common divisor, is available as a built-in routine in Raku.
Instead of finding the divisors for $A
or $B
, you can find them for their GCD only, as you can see in the solution submitted by Jan Krňávek:
sub common-factors( +@a ) {
my $gcd = [gcd] @a;
1, 2 ... $gcd
andthen .grep: $gcd %% *
}
Or in Kang-min Liu’s program:
sub common-factors (Int $a, Int $b) {
my $x = $a gcd $b;
return (1..$x).grep(-> $n { $x %% $n });
}
Mark Andreson expressed the same idea using a WhateverCode
block instead of a pointy block with an explicit signature:
my $gcd = $M gcd $N;
say (1..$gcd).grep($gcd %% *).join(", ").List;
Philip Hood showed an unexpected way of making some computations directly in the signature of the MAIN
function:
sub MAIN( Int $m = 18, Int $n = 12, $gc = $m gcd $n ) {
die( "too many args!" ) if @*ARGS.end > 1;
( 1 .. $gc ).grep(-> $k { $gc %% $k } ).say;
}
This trick can probably be used in a Raku Golf contest.
Laurent Rosenfeld added another improvement to check if the found value of GCD is a prime number:
sub common_factors (Int $a, Int $b) {
my $gcd = $a gcd $b;
return (1,) if $gcd == 1;
return ($gcd,) if $gcd.is-prime;
return (1..$gcd).grep($gcd %% *).unique;
}
Using junctions
The next group includes solutions that use junctions.
For example, look at Feng Chang’s code and the use of &
:
(1..min($M,$N)).grep({ ($M & $N) %% $_ }).say;
Markus Holzer reminds us that there’s an alternative form of creating junctions by using the built-in routine all
:
say "({ join ', ', grep all( $N, $M ) %% *, 1 ..^ max $N, $M })"
Bonus slide
The solution that was submitted by Julio de Castro requires special mentioning. A lot of -o fun
things happen here:
sub prefix:<∕>(\num) {
(1 ... num/2, +num).grep: num %% *
}
# intersects and returns result as sorted list
sub infix:<@∩>(\a, \b) {
(a ∩ b).keys.sort.list
}
sub MAIN(Int \a where * > 0, Int \b where * > 0) {
say ∕a @∩ ∕b
}
Video review
The full review of Task 1 is available on YouTube:
The timestamps for quick access to the review of each solution.
- 00:50 - Andrew Shitov
- 01:56 - Arne Sommer
- 03:45 - Feng Chang
- 05:02 - Jan Krnavek
- 06:21 - Kang-min Liu
- 07:10 - Mark Anderson
- 08:06 - Markus Holzer
- 09:03 - Philip Hood
- 10:12 - Simon Proctor
- 11:00 - Athanasius
- 13:12 - Colin Crain
- 14:58 - Jaldhar H. Vyas
- 15:34 - Julio de Castro
- 18:35 - Laurent Rosenfeld
- 19:32 - Myoungjin Jeon
- 20:50 - Roger Bell_West
- 22:40 - Ulrich Rieke
Task 2. Interleave String
This task was understood a bit differently by the participants. The main questions are, first, whether it is possible to only insert $B
into $A
, or the opposite is also allowed. The second idea is if we can split one or both of the input strings into smaller parts before searching for the result.
Let me not run through the solutions and their types here, but I still want to show you the output of the program by Athanasius. In the ‘Explanation’ section, you clearly see how the result was achieved:
$ raku challenge-082/athanasius/raku/ch-2.raku XXY XXZ XXXXYZ
Challenge 082, Task #2: Interleave String (Raku)
Input:
$A = "XXY"
$B = "XXZ"
$C = "XXXXYZ"
Output: 1
EXPLANATION
$A = XX Y
$B = XX Z
$C = XXXXYZ
You will find more details about the solutions and other interesting findings there in the video review below.
Video review
The full review of Task 2 is available on YouTube:
The timestamps to the reviews of the individual solutions:
- 01:37 - Ulrich Rieke
- 03:55 - Roger Bell_West
- 06:39 - Myoungjin Jeon
- 10:25 - Julio de Castro
- 18:20 - Jaldhar H. Vyas
- 22:30 - Colin Crain
- 28:42 - Athanasius
- 31:52 - Simon Proctor
- 33:46 - Philip Hood
- 38:22 - Markus Holzer
- 40:56 - Mark Anderson
- 44:57 - Kang-min Liu
- 47:16 - Jan Krnavek
- 52:50 - Feng Chang
- 55:30 - Arne Sommer
- 57:32 - Andrew Shitov
If you want to participate in The Weekly Challenge, please contact us at perlweeklychallenge@yahoo.com.