by Arne Sommer

# Digital Frequalizer with Raku

 Published 11. December 2022.

This is my response to The Weekly Challenge #194.

## Challenge #194.1: Digital Clock

You are given time in the format `hh:mm` with one missing digit.

Write a script to find the highest digit between `0-9` that makes it valid time.

Example 1: ```Input: \$time = '?5:00' Output: 1 Since 05:00 and 15:00 are valid time and no other digits can fit in the missing place. ``` Example 2: ```Input: \$time = '?3:00' Output: 2 ``` Example 3: ```Input: \$time = '1?:00' Output: 9 ``` Example 4: ```Input: \$time = '2?:00' Output: 3 ``` Example 5: ```Input: \$time = '12:?5' Output: 5 ``` Example 6: ```Input: \$time = '12:5?' Output: 9 ```
File: digital-clock ```#! /usr/bin/env raku subset MissingTime where /^<[012\?]><[0..9\?]>\:<[0..5\?]><[0..9\?]>\$/; #  unit sub MAIN (MissingTime \$time where \$time.comb.Bag<?> == 1); #  die "Illegal time" if \$time.substr(0,1) eq "2" && \$time.substr(1,1) ne any <0 1 2 3 ?>; #  given \$time #  { when .substr(0,1) eq "?" && .substr(1,1) < 4 { say "2"; } # "?[0..3]:**" #  when .substr(0,1) eq "?" { say "1"; } # "?[4..9]:**" # [5a] when .substr(1,1) eq "?" && .substr(0,1) < 2 { say "9"; } # "[0..1]?:**" #  when .substr(1,1) eq "?" { say "3"; } # "2?:**" # [6a] when .substr(3,1) eq "?" { say "5"; } # "**:?*" #  when .substr(4,1) eq "?" { say "9"; } # "**:*?" #  } ```

 A grammar is ideal here, but I have chosen the lazier route of using a custom type (with `subset`).

Feel free to read «lazier» as «crazier». I use a `subset`, two `where` clauses, a `Bag`, a `substr`(ing) and an `any` junction - just to avoid a grammar.

See docs.raku.org/language/typesystem#index-entry-subset-subset for more information about `subset`.

 The custom type allows up to four question marks, and thus we use a `where` clause that ensures that there is one and only one of them. We do this be turning the string into a single letters, and then into a `Bag` - which is a hash like structure where the characters are the keys, end the frequency is the value. Then we look up the question mark, and there should be only one.

See docs.raku.org/type/Bag for more information about the `Bag` type.

 The subset (in ) took care of the first digit (0, 1 or 2), but the second one cannot be higher than 3 if the first one is 2. This check ensures that - or a question mark.

 Using `given`/`when`, which is Raku speak for «switch», gives compact code.

 The first character is a question mark. The highest value is either 2 or 1 [5a], depending on the second digit.

 The second character is a question mark. The highest value is either 9 or 3 [6a], depending on the first digit.

 The third digit has 5 as the highest value.

 The fourth digit has 9 as the highest value.

Running it:

```\$ ./digital-clock ?5:00 1 \$ ./digital-clock ?3:00 2 \$ ./digital-clock 1?:00 9 \$ ./digital-clock 2?:00 3 \$ ./digital-clock 12:?5 5 \$ ./digital-clock 12:5? 9 ```

Looking good.

## Challenge #194.2: Frequency Equalizer

You are given a string made of alphabetic characters only, `a-z`.

Write a script to determine whether removing only one character can make the frequency of the remaining characters the same.

Example 1: ```Input: \$s = 'abbc' Output: 1 since removing one alphabet 'b' will give us 'abc' where each alphabet frequency is the same. ``` Example 2: ```Input: \$s = 'xyzyyxz' Output: 1 since removing 'y' will give us 'xzyyxz'. ``` Example 2: ```Input: \$s = 'xzxz' Output: 0 since removing any one alphabet would not give us string with same frequency alphabet. ```
File: frequency-equalizer ```#! /usr/bin/env raku subset az where /^<[a..z]>+\$/; # [1a] unit sub MAIN (az \$s, :v(:\$verbose)); #  my @freq = \$s.comb.Bag.values.sort; #  say ": Frequency sorted: @freq[]" if \$verbose; @freq.push(@freq.pop - 1); #  say ": Frequency lowered: @freq[]" if \$verbose; say ( [==] @freq ) ?? 1 !! 0; #  ```

 Ensure that the input only conains klower case letters (a..z), using a custom type (set up in [1a]).

 Get the frequency of the used letters. The `Bag` gives a hash like structure (as explained in the first part of this challenge), and we apply `.values` to get just the values - or the frequencies. Then we sort the list, giving us the highest value at the end.

 Remove the highest value (with `pop` that takes the last value in the list), subtract one, and push the new value back in the list og frequencies.

 Now all the frequencies should be the same. We use `[==]` to check this. The Reduction Metaoperator `[]` inserts the given operator (the numeric eqality operator `==`) between each value in the list and collapses the whole shabang to a Boolean value. Finally we print «1» if they are equal, and «0» otherwise.

See docs.raku.org/language/operators#Reduction_metaoperators for more information about the Reduction Metaoperator `[]`.

Running it:

```\$ ./frequency-equalizer abbc 1 \$ ./frequency-equalizer xyzyyxz 1 \$ ./frequency-equalizer xzxz 0 ```

Looking good.

With verbode mode:

```\$ ./frequency-equalizer -v abbc : Frequency sorted: 1 1 2 : Frequency lowered: 1 1 1 1 \$ ./frequency-equalizer -v xyzyyxz : Frequency sorted: 2 2 3 : Frequency lowered: 2 2 2 1 \$ ./frequency-equalizer -v xzxz : Frequency sorted: 2 2 : Frequency lowered: 2 1 0 ```

And that's it.