1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
[< Previous 193](https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-193/james-smith) |
[Next 195 >](https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-195/james-smith)
# The Weekly Challenge 194 - *iffy* solutions
You can find more information about this weeks, and previous weeks challenges at:
https://theweeklychallenge.org/
If you are not already doing the challenge - it is a good place to practise your
**perl** or **raku**. If it is not **perl** or **raku** you develop in - you can
submit solutions in whichever language you feel comfortable with.
You can find the solutions here on github at:
https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-194/james-smith
# Task 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.***
## Solution
Both solutions today use an ***IIFE*** (Immediately Invoked Function Expression) pronounced *iffy*. To remove the need for temporary variables. Each takes as input the result of an array method, here `split` and in the 2nd task `sort`.
In this case we split the parameter into it's consitutant characters - the hours being in `0` & `1` and the minutes in `3` and `4`. Using a series of ternary operators we work out which position the "`?`" is in and work out what is the best digit for this place.
If the "`?`" is in one of the minute slots this is easy as the value is either `5` or `9`.
If it is in the hour slot we have to make sure the hour is less than 24. So if "`?`" is the first digit, we know that that can be a `2` only if the second digit is less than `4` and if it is in the second digit then the digit can only be `0` - `3` if the 1st digit is `2`.
```perl
sub digit_2359 {
sub {
$_[0] eq '?' ? ( $_[1]<4 ? 2 : 1 )
: $_[1] eq '?' ? ( $_[0]<2 ? 9 : 3 )
: $_[3] eq '?' ? 5
: 9
}->( split //, $_[0] );
}
```
My original code allowed `24:00` as a valid value - this gave a slightly more complicated sub...
```perl
sub digit_2400 {
sub {
$_[0] eq '?' ? ( $_[1]<4 ? 2 : $_[1]==4 && $_[3]==0 && $_[4]==0 ? 2 : 1 )
: $_[1] eq '?' ? ( $_[0]<2 ? 9 : $_[3]==0 && $_[4]==0 ? 4 : 3 )
: $_[3] eq '?' ? 5
: 9
}->( split //, $_[0] );
}
```
# Task 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.***
## Solution
Again we use and IIFE. This time taking the value of the sorted values from `%f` (being the frequencies of each letter).
For the method to be true. The sorted values must be:
* `n`, `n`, `n`, ...., `n`, `n+1`
In fact if we reverse the sort (switch `$a` and `$b` around in the comparison) we have:
* `n+1`, `n`, `n`, ...., `n`, `n`
So check to see if the first is one more than the second and the second is the same
as the last.
```perl
sub check {
my %f; $f{$_} ++ for split //, $_[0];
sub { @_>2 && $_[0]==$_[1]+1 && $_[-1]==$_[1] }->(sort {$b<=>$a} values %f) || 0;
}
```
|