This is my response to The Weekly Challenge #196.
@list
.
Pattern 132
. Return
empty array if none found.
i < j < k and a[i] < a[k] < a[j]
.
Input: @list = (3, 1, 4, 2)
Output: (1, 4, 2) respect the Pattern 132.
Example 2:
Input: @list = (1, 2, 3, 4)
Output: () since no susbsequence can be found.
Example 3:
Input: @list = (1, 3, 2, 4, 6, 5)
Output: (1, 3, 2) if more than one subsequence found then return the
first.
Example 4:
Input: @list = (1, 3, 4, 2)
Output: (1, 3, 2)
#! /usr/bin/env raku
unit sub MAIN (*@list where @list.elems > 0 # [1]
&& all(@list) ~~ /^<[1..9]><[0..9]>*$/);
my $end = @list.elems - 1; # [2]
for 0 .. $end - 2 -> $i # [3]
{
for $i + 1 .. $end - 1 -> $j # [4]
{
for $j + 1 .. $end -> $k # [5]
{
if @list[$i] < @list[$k] < @list[$j] # [6]
{
say "(@list[$i], @list[$j], @list[$k])"; # [6a]
exit; # [6b]
}
}
}
}
say "()"; # [7]
[1] A slurpy array, with at least one element. I have decided to allow posittive integers only, as the examples stick to that subset of the integers mentioned in the challenge.
[2] The index of the last element, as we use it in the three loops below.
[3] The i
value can span the entire index range, except the last two - as we
have to leave room for j
and k
.
[4] The j
value starts right after i
. We stop one index short
of the edge, leaving room for k
.
[5] The k
value takes whatever is left, and iterates over those indices.
[6] Check if the values with the given indices satisfy the Pattern 132 rule. If they do, print the values [6a] and exit [6b]. If not, do nothing. I.e. go on.
[7] We come here if none of the iterations caused a match (and thus a program termination
caused by exit
). This means a failure, so we print the required empty parens.
Running it:
$ ./pattern132 3 1 4 2
(1, 4, 2)
$ ./pattern132 1 2 3 4
()
$ ./pattern132 1 3 2 4 6 5
(1, 3, 2)
$ ./pattern132 1 3 4 2
(1, 3, 2)
Looking good.
@array
.
Number Range
i.e [x, y] represent range
all integers from x
and y
(both inclusive).
Input: @array = (1,3,4,5,7)
Output: [3,5]
Example 2:
Input: @array = (1,2,3,6,7,9)
Output: [1,3], [6,7]
Example 3:
Input: @array = (0,1,2,4,5,6,8,9)
Output: [0,2], [4,6], [8,9]
#! /usr/bin/env raku
unit sub MAIN (*@array where @array.elems > 1 # [1]
&& all(@array) ~~ /^<[0..9]>+$/ # [2]
&& [<] @array); # [3]
my @ranges; # [4]
my $from = @array.shift.Int; # [5]
my $to = $from; # [6]
while @array # [7]
{
my $next = @array.shift.Int; # [8]
if $next == $to + 1 # [9]
{
$to = $next; # [9a]
}
else # [10]
{
@ranges.push([$from, $to]) if $to > $from; # [10a]
$from = $to = $next; # [10b]
}
}
@ranges.push([$from, $to]) if $to > $from; # [11]
say @ranges.raku; # [12]
[1] At least two elements.
[2] All of them must be non-negative integers, even if the challenge does not explicitly exclude negative values.
[3] The list must be sorted, in ascending order.
The Reduction Metaoperator []
is ideal here.
See
docs.raku.org/language/operators#Reduction_metaoperators for more
information about the Reduction Metaoperator []
.
[4] The result (a list of ranges) will end up here.
[5] Get the first value. The trailing .Int
coercer gets
rid of the pesky IntStr
type, which we get courtesy of the command line
input.
See
docs.raku.org/type/IntStr for
more information about the IntStr
type.
[8] The last value of the current range. This is initially the same as the start value, giving a range of one value - which is not a range at all.
[7] As long as we have unfinished business (i.e. values yet to be parsed).
[8] Get a new (unparsed) value.
[9] Does the new value fit in as thevery next value in the current range? If so, adjust the upper limit of the range accordingly.
[10] If not, add the current range to the result - if it is a range (e.g. if the start and end values differ) [10a], and initialise the current range with the new start value.
[11] When we are finished parsing the values, add the current range to the result list - if it is a range.
[12] Print the result using the raku
method to
give a readable output.
See
docs.raku.org/routine/raku
for more information about the raku
method.
$ ./range-list 1 3 4 5 7
[[3, 5],]
$ ./range-list 1 2 3 6 7 9
[[1, 3], [6, 7]]
$ ./range-list 0 1 2 4 5 6 8 9
[[0, 2], [4, 6], [8, 9]]
Looking good. Except the extra brackets (and the trailing comma for the first one), but that is just a presentation quibble...
And that's it.