Perl Weekly Challenge: Week 378
Challenge 1:
Second Largest Digit
You are given an alphanumeric string.
Write a script to find the second largest distinct digit in the given string. Return -1 if none found.
Example 1
Input: $str = "aaaaa77777"
Output: -1
The only digit in the given string is 7 and there is no second digit.
Example 2
Input: $str = "abcde"
Output: -1
No numerical digits in the given string.
Example 3
Input: $str = "9zero8eight7seven9"
Output: 8
Example 4
Input: $str = "xyz9876543210"
Output: 8
Example 5
Input: $str = "4abc4def2ghi8jkl2"
Output: 4
We can do this in one line of Raku. The salient part is a call to .match() on
the first command-line argument that looks for and catpures digits and returns them
in a sequence of Match objects. These are converted to integers with the hyper
operator ».Int. They are .sort()ed in descending numeric order and duplicates
are removed with.unique(). All this has been wrapped in parentheses so we can
treat it as a List. The second value in the list is printed with by the say()
at the beginning of the code or if it is not defined (//) the value -1 is printed instead.
say (@*ARGS[0].match(/(\d)/,:g)».Int.sort({ $^b <=> $^a }).unique)[1] //-1
The Perl version is also one line but longer and more complicated so I have split it up into several lines for this description.
The complication is caused by our lack of .unique(). We work around it by
creating a Hash.
my %a;
Digits are matched and captured by a regular expression as in Raku but each digit is treated as a key in the hash. The value of the key is incremented with each occurrence.
for my $i (shift =~ /(\d)/g) {
$a{$i}++
}
When the process is complete, the keys of the hash will be unique digits found in the input. Now the rest of the code can behave the same as in Raku.
say [sort {$b <=> $a} keys %a]->[1] // -1
Challenge 2:
Sum of Words
You are given three strings consisting of lower case English letters ‘a’ to ‘j’ only. The letter value of a = 0, b = 1, c = 3, etc.
Write a script to find if sum of first two strings return the third string.
Example 1
Input: $str1 = "acb", $str2 = "cba", $str3 = "cdb"
Output: true
$str1 = "acb" = 021
$str2 = "cba" = 210
$str3 = "cdb" = 231
$str1 + $str2 = $str3
Example 2
Input: $str1 = "aab", $str2 = "aac", $str3 = "ad"
Output: true
$str1 = "aab" = 001
$str2 = "aac" = 002
$str3 = "ad" = 03
Example 3
Input: $str1 = "bc", $str2 = "je", $str3 = "jg"
Output: false
$str1 = "bc" = 12
$str2 = "je" = 94
$str3 = "jg" = 96
Example 4
Input: $str1 = "a", $str2 = "aaaa", $str3 = "aa"
Output: true
$str1 = "a" = 0
$str2 = "aaaa" = 0000
$str3 = "aa" = 00
Example 5
Input: $str1 = "c", $str2 = "d", $str3 = "h"
Output: false
$str1 = "c" = 2
$str2 = "d" = 3
$str3 = "h" = 7
Example 6
Input: $str1 = "gfi", $str2 = "hbf", $str3 = "bdhd"
Output: true
$str1 = "gfi" = 658
$str2 = "hbf" = 715
$str3 = "bdhd" = 1373
I expected the solution to this challenge to contain more code but surprisingly, it turned out to be one (slightly long) line in both Raku and Perl. Once again, I will split up the line for clarity.
We get the first three command-line arguments as input and assign them to an array for
brevity. Then using .map() to iterate over this array, we .trans()form each
element from letters to the equivalent numbers.
my @a = @*ARGS[^3].map({ .trans([q{a}..q{j}] => [0..9]) });
Now all we need to do is add the first element to the second and see if it matches
the third element. (The answer will be either True or False.)
say @a[0] + @a[1] == @a[2]
For Perl we use the tr operator (which can be written as y—apparently for sed
compatability.) instead of .trans() but to the same effect.
my @a = map { y/a-j/0-9/; $_ } @ARGV[0..2];
Unfortunately as boolean values don't stringify in Perl, we have to provide our own
true and false.
say $a[0] + $a[1] == $a[2] ? "true" : "false"