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 073 of The Weekly Challenge!. For a quick overview, go through the original tasks and recap of the weekly challenge.
Task 1. Min Sliding Window
The task was to scan the array of integers @A
with a window of the given size $S
and print the minimum value on each step.
The submitted solutions demonstrated that that was one of the simplest tasks during the last few weeks of the Weekly Challenge. Nevertheless, there are several interesting moments that I would like to cover here in this review.
Using rotor
The first group of solutions includes those that used the built-in rotor
routine. One of the ways to work with it is to pass a pair, in which case you get the groups of overlapping lists with the given width. The key of the pair defines the width; the value stands for the gap between the series. If the gap is negative and its absolute value is 1 unit smaller than the width, we get exactly what we want in the task.
For instance, for the sample array and the window width of 3:
my @a = 1, 5, 0, 2, 9, 3, 7, 6, 4, 8;
say @a.rotor(3 => -2);
This program produces the following sequence of lists:
((1 5 0) (5 0 2) (0 2 9) (2 9 3) (9 3 7) (3 7 6) (7 6 4) (6 4 8))
Now, just find the minimum and print the result.
Using array slices
Another group is taking the sub-arrays using trivial computations of the indices of the first and the last elements within the window.
For example, in a loop using an array slice, as Noud Aldenhoven did it.
gather for 0..@A.elems-$S -> $i {
take min(@A[$i..$i+$S-1]);
}
Using maps
There is a cluster of solutions where scanning is done using the map
routine. For example, look at the nice one-liner by Ben Davies:
say (0...@array - $s).map({ @array.skip($_).head($s).min });
Finding the minimum
Not a surprise that the built-in min
routine was used widely. But its usage differs from one solution to another.
For example, Colin Crain used it in a WhateverCode
block inside a map
:
my @windows = @A.rotor($S=>-$S+1);
my @output = @windows.map( *.min );
A similar solution is proposed by Markus Holzer:
say join ' ', @A.rotor( $S => -($S - 1) ).map: *.min;
In my solution, I am using for
and calling .min
on a topicalized variable:
.min.say for @a.rotor($s => 1 - $s);
Collecting the results
In those solutions where the result is not printed immediately, the resulting values are usually collected in an array, and there are two main approaches to it. First, by push
ing the newly computed item. Look at Roger Bell_West’s variant for the reference:
my @out;
for (0..(@a.elems-$s)) -> $i {
push @out,min(@a[$i..$i+$s-1]);
}
Second, by using a gather
and take
pair, for example, as in Laurent Rosendeld’s code:
my @result = gather {
for 0..@a.elems - $s -> $i {
take min @a[$i..^$i + $s];
}
}
Bonus track
An outstanding solution is demonstrated by Jan Krnavek, where all the main steps of the algorithm are connected together using the andthen
infix:
sub min-sliding-window (@a, $s) {
@a
andthen .rotor: $s => - $s.pred
andthen .map: *.min
}
Video review
The full review of the solutions to the Task 1 is available on YouTube:
Starting from this week, I’ll be publishing the timestamps for quick access to the review of each solution.
- 01:00 — Ulrich Rieke
- 03:54 — Roger Bell_West
- 04:47 — Myoungjin Jeon
- 08:00 — Mohammad S Anwar
- 10:15 — Laurent Rosenfeld
- 11:35 — Javier Luque
- 12:30 — Jaldhar H. Vyas
- 13:57 — Colin Crain
- 15:32 — Athanasius
- 17:37 — Arne Sommer
- 19:35 — Simon Proctor
- 20:47 — Noud Aldenhoven
- 21:34 — Markus Holzer
- 21:58 — Mark Anderson
- 22:38 — Luca Ferrari
- 23:47 — Jason Messer
- 24:16 — Jan Krnavek
- 25:58 — Ben Davies
- 29:07 — Andrew Shitov
Additional materials
- Read more about
rotor
in the Raku documentation - Read more about
min
in the Raku documentation - The Pearls of Raku: The secrets of
min
(andmax
)
Task 2. Smallest Neighbour
In the second task, you are also working with an array of integers and for each of the items, you need to find the minimum item among the elements prior to the current one. If the current one is bigger than that minimum or if it is the first item in the array, print 0
.
To understand the task, you needed to examine the examples, but most of the participants dit it well; there is only one solution that missed that additional requirement.
Excerpts from the solutions
In the solutions, we again see similar ways of finding the minimum values of a part of an array. Collecting the result is done via gather
and take
or by push
ing or append
ing the elements to the end of the array.
To simplify finding the minimum, some participants used grep
to ignore all the items which are bigger than the current one. For example, you can see it in a solution by Mark Andreson:
@A.kv.map(-> $k,$v {(@A.head($k+1).grep(* < $v) or 0).min}).join(", ").List.say;
Or as Markus Holzer did it in his compact solution:
say join ' ', 0, gather for 1 .. +@A - 1 -> $i {
take .min with @A[ 0..$i-1 ].grep( * < @A[$i] ) or 0 };
By the way, Roger Bell_West demonstrated the method of computing the minumum without using any explicit comparisons. Just add the current minimum value to the new data set, and find the minimum again:
$wm=min($wm,@a[$i-1]);
Myoungjin Jeon reminds us how to mixin a role in Raku with but
:
role zero { method raku { "0" } }
. . .
$smallest < $c ?? $smallest !! $c but zero
Later, when you call the raku
method on a value, the role’s method is used for the elements where that role was applied:
say "Output: {@answer.map( *.raku ).map( *.Int ).Array.raku}"
Bonus track
As a side story, watch the deparsing and modifying the regular expression that Mohammad S Anwar used in his solution, where he takes the input data as a string:
sub MAIN(Str $list = "7, 8, 3, 12, 10") {
say $list;
smallest-neighbour($list).join(', ').say;
}
sub smallest-neighbour(Str $list is copy) {
die "ERROR: Invalid list [$list].\n"
unless $list ~~ /^[\s?\-?\d\,?\s?]+$/;
. . .
}
Video review
The full review of the solutions to the Task 2 is available on YouTube:
The timestamps to the reviews of the individual solutions:
- 01:50 — Andrew Shitov
- 03:42 — Ben Davies
- 10:00 — Jan Krnavek
- 18:37 — Jason Messer
- 20:04 — Luca Ferrari
- 23:02 — Mark Anderson
- 24:42 — Markus Holzer
- 26:30 — Noud Aldenhoven
- 27:35 — Simon Proctor
- 29:18 — Arne Sommer
- 30:44 — Athanasius
- 32:51 — Colin Crain
- 36:17 — Jaldhar H. Vyas
- 38:33 — Javier Luque
- 40:22 — Laurent Rosenfeld
- 42:00 — Mohammad S Anwar
- 49:11 — Myoungjin Jeon
- 56:11 — Roger Bell_West
- 57:40 — Ulrich Rieke
Additional materials
- Read more about
gather
andtake
in the Raku documentation - Read more about mixins of roles in the Raku documentation
- The Pearls of Raku: Triangular reduction metaoperator
BLOGS
Andrew Shitov, Arne Sommer, Colin Crain, Jaldhar H. Vyas, Javier Luque, Luca Ferrari, Laurent Rosenfeld, Mohammad S Anwar and Roger Bell_West.
If you want to participate in The Weekly Challenge, please contact us at perlweeklychallenge@yahoo.com.