This is my response to The Weekly Challenge #225.
@list
.
Input: @list = ("Perl and Raku belong to the same family.",
"I love Perl.",
"The Perl and Raku Conference.")
Output: 8
Example 2:
Input: @list = ("The Weekly Challenge.",
"Python is the most popular guest language.",
"Team PWC has over 300 members.")
Output: 7
#! /usr/bin/env raku
unit sub MAIN (*@list); # [1]
say @list>>.split(" ")>>.elems.max; # [2]
[1] A slurpy array collecting all the sentences. Note the missing
where @list.elems > 0
clause, thus allowing no input.
[2] Apply split
on each sentence
(courtesy of the >>.
method invocation. We split on a
single space, as requested, instead of using the more forgiving
words
method. Then we use elems
on each
sentence (which is now a list of words) to get the length. This
returns a list of lengths, one for each sentence. And finally we use
max
to get the highest value.
See
docs.raku.org/routine/words
for more information about words
.
Running it:
$ ./max-words "Perl and Raku belong to the same family." "I love \
Perl." "The Perl and Raku Conference."
8
$ ./max-words "The Weekly Challenge." "Python is the most popular \
guest language." "Team PWC has over 300 members."
7
Looking good.
@ints
.
@ints = (a, b, c, d, e)
@left = (0, a, (a+b), (a+b+c))
@right = ((c+d+e), (d+e), e, 0)
@left_right_sum_diff = ( | 0 - (c+d+e) |,
| a - (d+e) |,
| (a+b) - e |,
| (a+b+c) - 0 | )
Example 1:
Input: @ints = (10, 4, 8, 3)
Output: (15, 1, 11, 22)
@left = (0, 10, 14, 22)
@right = (15, 11, 3, 0)
@left_right_sum_diff = ( |0-15|, |10-11|, |14-3|, |22-0|)
= (15, 1, 11, 22)
Example 2:
Input: @ints = (1)
Output: (0)
@left = (0)
@right = (0)
@left_right_sum_diff = ( |0-0| ) = (0)
Example 3:
Input: @ints = (1, 2, 3, 4, 5)
Output: (14, 11, 6, 1, 10)
@left = (0, 1, 3, 6, 10)
@right = (14, 12, 9, 5, 0)
@left_right_sum_diff = ( |0-14|, |1-12|, |3-9|, |6-5|, |10-0|)
= (14, 11, 6, 1, 10)
The formulae in the challenge is wrong; as it has five input values and only four as output. These values should be identical; as shown by the three examples.
The trick here is recognizing the pattern, and also that the right column is the same as the left one, but in the other direction (from the end, and not the beginning). These observations make it easyish.
File: lrsd
#! /usr/bin/env raku
unit sub MAIN (*@int, :v(:$verbose)); # [1]
my $size = @int.elems; # [2]
my @reverse = @int.reverse; # [3]
my @left = (0,); # [4]
my @right = (0,); # [5]
for 0 .. $size -2 -> $i # [6]
{
@left.push: sum(@int[0 .. $i]); # [7]
@right.push: sum(@reverse[0 .. $i]); # [8]
}
@right .= reverse; # [9]
say ":Left: @left[]\n:Right: @right[]" if $verbose;
say (@left Z @right).map({ ( $_[0] - $_[1] ).abs }); # [10]
[1] A slurpy array collecting the values. Note that no arguments is ok.
[2] The number of input elements; which is also the number of output elements.
[3] As the right column is the same as the left one - from the other direction.
[4] The first value is zero.
[5] Ditto.
[6] Iterate over the rest of the values.
[7] The left value to add, using sum
to add them
all together. Note the use of an array slice (a part of an array) to get the
requested values.
See
docs.raku.org/routine/sum
for more information about sum
.
[8] The right (as in non-left; but it is actually the right one, as in non-wrong, as well) value to add.
[9] Reverse the right column.
[10]
We use the zipper operator Z
to merge the two
lists, giving us a list of pair values. Then we use map
to reduce
each pair to a single value (left minus right, and get rid of the sign with
abs
). Then
print that list.
See
docs.raku.org/routine/Z
for more information about the infix zip operator Z
.
See
docs.raku.org/routine/abs
for more information about abs
.
Running it:
$ ./lrsd 10 4 8 3
(15 1 11 22)
$ ./lrsd 1
(0)
$ ./lrsd 1 2 3 4 5
(14 11 6 1 10)
Looking good, except the missing commas...
With verbose mode:
$ ./lrsd -v 10 4 8 3
:Left: 0 10 14 22
:Right: 15 11 3 0
(15 1 11 22)
$ ./lrsd -v 1
:Left: 0
:Right: 0
(0)
$ ./lrsd -v 1 2 3 4 5
:Left: 0 1 3 6 10
:Right: 14 12 9 5 0
(14 11 6 1 10)
Running it without arguments gives a list containing a zero:
$ ./lrsd
(0)
$ ./lrsd -v
:Left: 0
:Right: 0
(0)
We should perhaps get an empty list here...
Let us fix that, and add the commas as well.
File: lrsd-zero
#! /usr/bin/env raku
unit sub MAIN (*@int, :v(:$verbose));
if @int.elems == 0 # [1]
{
say '()';
exit;
}
my $size = @int.elems;
my @reverse = @int.reverse;
my @left = (0,);
my @right = (0,);
for 0 .. $size -2 -> $i
{
@left.push: sum(@int[0 .. $i]);
@right.push: sum(@reverse[0 .. $i]);
}
@right .= reverse;
say ":Left: @left[]\n:Right: @right[]" if $verbose;
say '(', (@left Z @right).map({ ( $_[0] - $_[1] ).abs }).join(", "), ')'; # [2]
[1] We treat no arguments as a special case.
[2] Note the explicit parens this time, as we use join
on the list
to add commas. The original program had Raku adding the parens for us automagically
on array stringification.
And that's it.