This is my response to The Weekly Challenge #325.
0
or/and 1
.
1
in the
given array.
Input: @binary = (0, 1, 1, 0, 1, 1, 1)
Output: 3
Example 2:
Input: @binary = (0, 0, 0, 0)
Output: 0
Example 3:
Input: @binary = (1, 0, 1, 0, 1, 1)
Output: 2
#! /usr/bin/env raku
subset BinaryDigit of Int where * eq any(0,1); # [1]
unit sub MAIN (*@binary where @binary.elems >= 1 # [1b]
&& all(@binary) ~~ BinaryDigit, # [1a]
:v(:$verbose));
my @ones = @binary.join.split(/0+/); # [2]
say ": One strings: { @ones.join(",") }" if $verbose;
say @ones.max.chars; # [3]
[1] We define a custom type for binary digits with
subset
, and apply that to the input [1a] - of which there must be
at least one [1b].
See docs.raku.org/routine/subset for more information about subset
.
[2] We do not care about the zeroes, so can split the string we get with
join
(on the array) on the one or more zeroes regex
/0+/
. That gives us a list of strings with consecutive 1
s.
[3] We are looking for the longest string in the array from [2]. That is
also the highest value, so I use max
to get it. The challenge
wanted the number of digits, so we use chars
to get that.
Running it:
$ ./consecutive-one 0 1 1 0 1 1 1
3
$ ./consecutive-one 0 0 0 0
0
$ ./consecutive-one 1 0 1 0 1 1
2
Looking good.
With verbose mode:
$ ./consecutive-one -v 0 1 1 0 1 1 1
: One strings: ,11,111
3
$ ./consecutive-one -v 0 0 0 0
: One strings: ,
0
$ ./consecutive-one -v 1 0 1 0 1 1
: One strings: 1,1,11
2
Note that the first comma in the first example is caused by the first zero in the input. That leads to an undefined value up front in the result, thus giving us the strange comma. It does not matter for the algorithm.
Note that the single comma in the second example has the same cause as the one above. This one also does not matter for the algorithm.
Input: @prices = (8, 4, 6, 2, 3)
Output: (4, 2, 4, 2, 3)
Item 0:
The item price is 8.
The first time that has price <= current item price is 4.
Final price = 8 - 4 => 4
Item 1:
The item price is 4.
The first time that has price <= current item price is 2.
Final price = 4 - 2 => 2
Item 2:
The item price is 6.
The first time that has price <= current item price is 2.
Final price = 6 - 2 => 4
Item 3:
The item price is 2.
No item has price <= current item price, no discount.
Final price = 2
Item 4:
The item price is 3.
Since it is the last item, so no discount.
Final price = 3
Example 2:
Input: @prices = (1, 2, 3, 4, 5)
Output: (1, 2, 3, 4, 5)
Example 3:
Input: @prices = (7, 1, 1, 5)
Output: (6, 0, 1, 5)
Item 0:
The item price is 7.
The first time that has price <= current item price is 1.
Final price = 7 - 1 => 6
Item 1:
The item price is 1.
The first time that has price <= current item price is 1.
Final price = 1 - 1 => 0
Item 2:
The item price is 1.
No item has price <= current item price, so no discount.
Final price = 1
Item 3:
The item price is 5.
Since it is the last item, so no discount.
Final price = 5
#! /usr/bin/env raku
unit sub MAIN (*@prices where @prices.elems >= 1 # [1]
&& all(@prices) ~~ UInt, # [1a]
:v(:$verbose));
my @final; # [2]
for ^@prices.elems -> $i # [3]
{
my $price = @prices[$i]; # [4]
my $lower = @prices[$i+1 .. Inf].grep(* <= $price).first; # [5]
if defined $lower # [6]
{
my $new = $price - $lower; # [6a]
say ": Price: $price - lower $lower = $new" if $verbose;
@final.push: $new; # [6b]
}
else # [7]
{
say ": Price: $price -> no lower = $price" if $verbose;
@final.push: $price; # [7a]
}
}
say @final;
[1] A slurpy array with at least one element, all of which must be unsigned inters [1a].
See docs.raku.org/type/UInt for more information about the UInt
type.
[2] The discounted prices will end up here.
[3] Iterate over all the price indices to process.
[4] Get the current price.
[5]
Get all the prices to the right of it (the current price),
then use grep
to keep only those that are equal or lower to it
(the current price), and finally use first
to get the first (or
leftmost) one.
See docs.raku.org/routine/grep for more information about grep
.
See docs.raku.org/routine/first for more information about first
.
[6] Do we have a lower or equal number (i.e. a discount base). If so, compute the discounted value [6a] and add it to the new price array.
[7] No discount? Use the price itself (undiscounted) [7a].
Running it:
$ ./final-price 8 4 6 2 3
[4 2 4 2 3]
$ ./final-price 1 2 3 4 5
[1 2 3 4 5]
$ ./final-price 7 1 1 5
[6 0 1 5]
Looking good.
With verbose mode:
$ ./final-price -v 8 4 6 2 3
: Price: 8 - lower 4 = 4
: Price: 4 - lower 2 = 2
: Price: 6 - lower 2 = 4
: Price: 2 -> no lower = 2
: Price: 3 -> no lower = 3
[4 2 4 2 3]
$ ./final-price -v 1 2 3 4 5
: Price: 1 -> no lower = 1
: Price: 2 -> no lower = 2
: Price: 3 -> no lower = 3
: Price: 4 -> no lower = 4
: Price: 5 -> no lower = 5
[1 2 3 4 5]
$ ./final-price -v 7 1 1 5
: Price: 7 - lower 1 = 6
: Price: 1 - lower 1 = 0
: Price: 1 -> no lower = 1
: Price: 5 -> no lower = 5
[6 0 1 5]
And that's it.