This is my response to The Weekly Challenge #366.
Input: @array = ("a", "ap", "app", "apple", "banana"), $str = "apple"
Output: 4
Example 2:
Input: @array = ("cat", "dog", "fish"), $str = "bird"
Output: 0
Example 3:
Input: @array = ("hello", "he", "hell", "heaven", "he"), $str = "hello"
Output: 4
Example 4:
Input: @array = ("", "code", "coding", "cod"), $str = "coding"
Output: 3
Example 5:
Input: @array = ("p", "pr", "pro", "prog", "progr", "progra", "program"), $str = "program"
Output: 7
#! /usr/bin/env raku
unit sub MAIN ($str where $str ~~ /^ <[a..z]> $/, # [1]
*@array where @array.elems > 0, # [2]
:v(:$verbose));
my @ok = @array.grep({ $str.starts-with: $_ }); # [3]
say ": Matches: { @ok.join(", ") }" if $verbose;
say @ok.elems; # [4]
[1] The string, containing English letters only, comes first.
[2] A slurpy array taking the rest of the input. No restrictions on the input on these.
[3] Use grep to only keep the words where the string
starts with (starts-with) the current word.
See docs.raku.org/routine/starts-with for more information about starts-with.
[4] Print the number of matching words.
Running it:
$ ./count-prefixes -v apple a ap app apple banana
: Matches: a, ap, app, apple
4
$ ./count-prefixes bird cat dog fish
0
$ ./count-prefixes hello hello he hell heaven he
4
$ ./count-prefixes coding "" code coding cod
3
$ ./count-prefixes program p pr pro prog progr progra program
7
Looking good.
With verbose mode:
$ ./count-prefixes apple -v a ap app apple banana
4
$ ./count-prefixes -v bird cat dog fish
: Matches:
0
$ ./count-prefixes -v hello hello he hell heaven he
: Matches: hello, he, hell, he
4
$ ./count-prefixes -v coding "" code coding cod
: Matches: , coding, cod
3
$ ./count-prefixes -v program p pr pro prog progr progra program
: Matches: p, pr, pro, prog, progr, progra, program
7
It is possible to make the program shorter, by combining rows [3]
and {4], essentially giving a one liner - except for the unit preamble.
Input: $time = "?2:34"
Output: 3
0 -> "02:34" valid
1 -> "12:34" valid
2 -> "22:34" valid
Example 2:
Input: $time = "?4:?0"
Output: 12
Hours: tens digit ?, ones digit 4 -> can be 04, and 14 (2 possibilities)
Minutes: tens digit ?, ones digit 0 -> tens can be 0-5 (6 possibilities)
Total: 2 × 6 = 12
Example 3:
Input: $time = "??:??"
Output: 1440
Hours: from 00 to 23 -> 24 possibilities
Minutes: from 00 to 59 -> 60 possibilities
Total: 24 × 60 = 1440
Example 4:
Input: $time = "?3:45"
Output: 3
If tens digit is 0 or 1 -> any ones digit works, so 03 and 13 are valid
If tens digit is 2 -> ones digit must be 0-3, but here ones digit is 3, so 23 is valid
Therefore: 0,1,2 are all valid -> 3 possibilities
Example 5:
Input: $time = "2?:15"
Output: 4
Tens digit is 2, so hours can be 20-23
Ones digit can be 0,1,2,3 (4 possibilities)
Therefore: 4 valid times
#! /usr/bin/env raku
unit sub MAIN ($time where $time ~~ /^ <[012\?]> <[0..9\?]> ":"
<[0..5\?]> <[0..9\?]> $/, # [1]
:v(:$verbose));
my $hh-count = 1; # [2]
my $mm-count = 1; # [2a]
my ($hh, $mm) = $time.split(":"); # [3]
die "Illegal hour value $hh" if $hh ~~ /\d\d/ && $hh > 23; # [4]
if $hh eq "??" # [5]
{
$hh-count = 24; # [5a]
}
elsif $hh.substr(0,1) eq "?" # [6]
{
$hh-count = $hh.substr(1,1) <= 3 ?? 3 !! 2; # [6a]
}
elsif $hh.substr(1,1) eq "?" # [7]
{
$hh-count = $hh.substr(0,1) == 2 ?? 4 !! 10; # [7a]
}
if $mm eq "??" # [8]
{
$mm-count = 60; # [8a]
}
elsif $mm.substr(0,1) eq "?" # [9]
{
$mm-count = 6; # [9a]
}
elsif $mm.substr(1,1) eq "?" # [10]
{
$mm-count = 10; # [10a]
}
if $verbose
{
say ": HH: $hh count: $hh-count";
say ": MM: $mm count: $mm-count";
}
say $hh-count * $mm-count; # [11]
[1] The time, verified against this regex. First a digit 0, 1, 2 or a question mark, then a digit or a question mark, then a colon, then a digit 0, 1, 2, 3, 4, 5 or a question mark, and finally a digit or a question mark. Note that e.g. «24:00» will pass this test, but [4] will stop it.
[2] The number of hour and minute [2a] iterations will end up here.
[3] Extract the hour and minute parts.
[4] Exit if the hour is greater than 23.
[5] Is both hour digits question marks? If so, we have 24 possibilities.
[6] Is the first one a question mark? If so, we have 3 possibilities if the following digit is 0, 1, 2 or 3 - and 2 otherwise. (As 24 is illegal, and 14 is ok.)
[7] Is the second one a question mark? If so, we have 4 possibilities if the digit is 2 (as in 20, 21, 22 and 23) and 10 otherwise (as both 0? and 1? takes 0-9).
[8] Is both minute digits question maks? If so, we have 60 possibilities.
[9] Is the first one a question mark? If so, we have 6 possibilities.
[10] Is the second one a question mark? If so, we have 10 possibilities.
[11] Print the result, the product of the hour and minute possibilites.
Running it:
$ ./valid-times "?2:34"
3
$ ./valid-times "?4:?0"
12
$ ./valid-times "??:??"
1440
$ ./valid-times "?3:45"
3
$ ./valid-times "2?:15"
4
Looking good.
With verbose mode:
$ ./valid-times -v "?2:34"
: HH: ?2 count: 3
: MM: 34 count: 1
3
$ ./valid-times -v "?4:?0"
: HH: ?4 count: 2
: MM: ?0 count: 6
12
$ ./valid-times -v "??:??"
: HH: ?? count: 24
: MM: ?? count: 60
1440
$ ./valid-times -v "?3:45"
: HH: ?3 count: 3
: MM: 45 count: 1
3
$ ./valid-times -v "2?:15"
: HH: 2? count: 4
: MM: 15 count: 1
4
And that's it.