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

(Full code on Github.)

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

(Full code on Github.)

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 Lists 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

(Full code on Github.)

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;

(Full code on Github.)