Perl Weekly Challenge: Week 319
Challenge 1:
Word Count
You are given a list of words containing alphabetic characters only.
Write a script to return the count of words either starting with a vowel or ending with a vowel.
Example 1
Input: @list = ("unicode", "xml", "raku", "perl")
Output: 2
The words are "unicode" and "raku".
Example 2
Input: @list = ("the", "weekly", "challenge")
Output: 2
Example 3
Input: @list = ("perl", "python", "postgres")
Output: 0
Regular expressions make this easy in Raku and Perl. In both languages we iterate over the input filtering out the elements which start or end with a vowel (I didn't consider upper-case vowels. It is not neccessary for the examples but easy to add if needed.) Then we count how many elements found and print the result.
@*ARGS.grep({ $_.match(/^ <[aeiou]> || <[aeiou]> $/) }).elems.say
The only extra thing we have to do for Perl is add 0 +
in front of greo()
to force scalar context and give the count of
elements rather than the elements themselves.
say 0 + grep { /^[aeiou]|[aeiou]$/ } @ARGV
Challenge 2:
Minimum Common
Write a sc>ript to return the minimum integer common to both arrays. If none found return -1.
Example 1
Input: @array_1 = (1, 2, 3, 4)
@array_2 = (3, 4, 5, 6)
Output: 3
The common integer in both arrays: 3, 4
The minimum is 3.
Example 2
Input: @array_1 = (1, 2, 3)
@array_2 = (2, 4)
Output: 2
Example 3
Input: @array_1 = (1, 2, 3, 4)
@array_2 = (5, 6, 7, 8)
Output: -1
So what we need to do here is to find the intersection of the two arrays (as sets) and then the smallest element of the resulting set. Raku gives us all the tools to implement this as a one-liner.
We get the input from two command-line arguments which are strings of integers separated by spaces. So for instance, the
input for example 1 would look like this: "1 2 3 4" "3 4 5 6"
. The strings are split up into List
s of integers with
.words()
The intersection operator ∩
creates a new Set
with all the integers which are common to both lists. Because elements are stored in a Set
as Pairs
, we use .keys()
to get the actual values (not .values()
which is bit confusing.) Then .min()
gives us the smallest integer which we print with .say()
.
(@*ARGS[0].words ∩ @*ARGS[1].words).keys.min.say
This is good enough for examples 1 and 2 but fails for example 3. We get Inf
instead of -1
because apparently an empty
set has no numeric value so we cannot use .min()
. So I made the change shown below.
((@*ARGS[0].words ∩ @*ARGS[1].words).keys || (-1)).min.say
An empty set is False
so the right side of the logical OR operator (||
) is called. There I have a List with the solitary value -1
. Now .min()
works and -1
is printed.
The Perl solution is a lot longer than one line because we have to provide our own intersection()
and min()
functions.
my @array_1 = split /\s+/, shift;
my @array_2 = split /\s+/, shift;
say min(intersection(\@array_1, \@array_2)) || -1;