Perl Weekly Challenge: Week 239
Challenge 1:
Same String
You are given two arrays of strings.
Write a script to find out if the word created by concatenating the array elements is the same.
Example 1
Input: @arr1 = ("ab", "c")
@arr2 = ("a", "bc")
Output: true
Using @arr1, word1 => "ab" . "c" => "abc"
Using @arr2, word2 => "a" . "bc" => "abc"
Example 2
Input: @arr1 = ("ab", "c")
@arr2 = ("ac", "b")
Output: false
Using @arr1, word1 => "ab" . "c" => "abc"
Using @arr2, word2 => "ac" . "b" => "acb"
Example 3
Input: @arr1 = ("ab", "cd", "e")
@arr2 = ("abcde")
Output: true
Using @arr1, word1 => "ab" . "cd" . "e" => "abcde"
Using @arr2, word2 => "abcde"
Here's a Raku one-liner to solve this task. The biggest issue is how to input the two arrays in a command-line script.
I chose to make each one a string in which each element is separated by a comma and a space. So for example, the arguments for example 2 would look like: "ab, c" "ac, b"
Now all our code needs to do is .split()
those arguments back into arrays, .join()
them without spaces and compare them for equality. If they are equal, say()
will print out True
or otherwise, False
.
say @*ARGS[0].split(q{, }).join eq @*ARGS[1].split(q{, }).join
The Perl version would have been a bit too unwieldy to make into a one-liner so I spelled everything out.
my @arr1 = split q{, }, $ARGV[0];
my @arr2 = split q{, }, $ARGV[1];
say()
neads 0+
in front of it to prevent a warning about it being used as a function (which it is isn't it?? but anyway...)
and we have to explicitly print true and false because they aren't keywords like in Raku.
say 0+((join q{}, @arr1) eq (join q{}, @arr2)) ? 'true' : 'false';
Challenge 2:
Consistent Strings
You are given an array of strings and allowed string having distinct characters.
A string is consistent if all characters in the string appear in the string allowed.
Write a script to return the number of consistent strings in the given array.
Example 1
Input: @str = ("ad", "bd", "aaab", "baa", "badab")
$allowed = "ab"
Output: 2
Strings "aaab" and "baa" are consistent since they only contain characters 'a' and 'b'.
Example 2
Input: @str = ("a", "b", "c", "ab", "ac", "bc", "abc")
$allowed = "abc"
Output: 7
Example 3
Input: @str = ("cc", "acd", "b", "ba", "bac", "bad", "ac", "d")
$allowed = "cad"
Output: 4
Strings "cc", "acd", "ac", and "d" are consistent.
This time the Perl solution is a one-liner and Raku is longer so let's start with Perl.
The first command-line argument becomes the allowed string and the rest of the arguments become an array
of strings to check for consistency. Frustratingly, you can't create this array with an array slice like @ARGV[1 .. -1]
so we use the splice()
function. The allowed string is interpolated into a regular expression which grep()
uses to filter
out consistent strings. scalar()
in array context counts how such strings were found and say()
prints the result.
say scalar grep {/^["$ARGV[0]"]+$/} splice @ARGV,1
In theory I should be able to translate the Perl code into one line of Raku but try as I might, I was not able to interpolate
$allowed
into a character class without errors.
sub MAIN(
$allowed,
*@str
) {
But oddly enough, if I did it as two lines where the first creates a ragular expression which interpolates $allowed
into a character class...
my $class = "<[$allowed]>";
...and the second line interpolates that regular expression into another one, it works.
@str.grep({ /^ <$class>+ $/ }).elems.say;
}
After all this time, I still don't understand regular expressions in Raku very well.