Count the Times
with Raku

by Arne Sommer

Count the Times with Raku

[390] Published 25. March 2026.

This is my response to The Weekly Challenge #366.

#366.1 Count Prefixes You are given an array of words and a string (contains only lowercase English letters).

Write a script to return the number of words in the given array that are a prefix of the given string.

Example 1:
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
File: count-prefixes
#! /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.

#366.2 Valid Times You are given a time in the form ‘HH:MM’. The earliest possible time is ‘00:00’ and the latest possible time is ‘23:59’. In the string time, the digits represented by the ‘?’ symbol are unknown, and must be replaced with a digit from 0 to 9.

Write a script to return the count different ways we can make it a valid time.

Example 1:
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
File: 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.