Perl Weekly Challenge 231.

My solutions (task 1 and task 2 ) to the The Weekly Challenge - 231.

Task 1: Min Max

Submitted by: Mohammad S Anwar
You are given an array of distinct integers.

Write a script to find all elements that is neither minimum
nor maximum. Return -1 if you can’t.

Example 1
Input: @ints = (3, 2, 1, 4)
Output: (3, 2)

The minimum is 1 and maximum is 4 in the given array. So (3, 2)
is neither min nor max.

Example 2
Input: @ints = (3, 1)
Output: -1
Example 3
Input: @ints = (2, 1, 3)
Output: (2)

The minimum is 1 and maximum is 3 in the given array. So 2 is neither min nor max.

A simple solution may be obtained by first finding the minimum and the maximum of the array and using them to filter the rest of the list. I can use minmax from List::MoreUtils.

Example 1:

perl -MList::MoreUtils=minmax -E '
@x=@ARGV; ($l,$h)=minmax(@x); @y=grep {$_!=$l && $_!=$h} @x; say "(@x) -> ", join " ", @y?"(@y)":-1
' 3 2 1 4

Results:

(3 2 1 4) -> (3 2)

Example 2:

perl -MList::MoreUtils=minmax -E '
@x=@ARGV; ($l,$h)=minmax(@x); @y=grep {$_!=$l && $_!=$h} @x; say "(@x) -> ", join " ", @y?"(@y)":-1
' 3 1

Results:

(3 1) -> -1

Example 3:

perl -MList::MoreUtils=minmax -E '
@x=@ARGV; ($l,$h)=minmax(@x); @y=grep {$_!=$l && $_!=$h} @x; say "(@x) -> ", join " ", @y?"(@y)":-1
' 2 1 3

Results:

(2 1 3) -> (2)

Assuming that the list is really made of unique integers, and if I don’t care about the order of the result, I can just order the list and drop its first and last elements.

Examples:

perl -E '@x=sort @ARGV; shift @x; pop @x; say "(@ARGV) -> ", @x?"(@x)":-1;' 3 2 1 4
perl -E '@x=sort @ARGV; shift @x; pop @x; say "(@ARGV) -> ", @x?"(@x)":-1;' 3 1
perl -E '@x=sort @ARGV; shift @x; pop @x; say "(@ARGV) -> ", @x?"(@x)":-1;' 2 1 3

Results:

(3 2 1 4) -> (2 3)
(3 1) -> -1
(2 1 3) -> (2)

For the full code I go back to the first solution, as it is more permissive about repetitions.

 1  # Perl weekly challenge 231
 2  # Task 1:  Min Max
 3  #
 4  # See https://wlmb.github.io/2023/08/20/PWC231/#task-1-min-max
 5  use v5.36;
 6  use List::MoreUtils qw(minmax);
 7  die <<~"FIN" unless @ARGV;
 8      Usage: $0 N1 [N2...]
 9      to find all numbers Ni that are not minimum nor maximum.
10      FIN
11  my @in=@ARGV;
12  my ($low,$high)=minmax(@in);
13  my @out=grep {$_!=$low && $_!=$high} @in;
14  say "(@in) -> ", join " ", @out?"(@out)":-1

Example:

./ch-1.pl 3 2 1 4
./ch-1.pl 3 1
./ch-1.pl 2 1 3

Results:

(3 2 1 4) -> (3 2)
(3 1) -> -1
(2 1 3) -> (2)

Task 2: Senior Citizens

Submitted by: Mohammad S Anwar
You are given a list of passenger details in the form
“9999999999A1122”, where 9 denotes the phone number, A the sex,
1 the age and 2 the seat number.

Write a script to return the count of all senior citizens
(age >= 60).

Example 1
Input: @list = ("7868190130M7522","5303914400F9211","9273338290F4010")
Ouput: 2

The age of the passengers in the given list are 75, 92 and 40.
So we have only 2 senior citizens.

Example 2
Input: @list = ("1313579440F2036","2921522980M5644")
Ouput: 0

First I change the form to a RE to extract age.

perl -E '
$f="9999999999A1122"; $f=~s/[9A2]/./g;$f=~s/(1+)/($1)/; $f=~s/1/\\d/g; $f=~s/^(.*)$/^$1\$/; say $f;'

Results:

^...........(\d\d)..$

Now I use it, extract the ages and filter by age. Example 1:

perl -E 'say "@ARGV -> ", 0+grep {/^...........(\d\d)..$/; $1>=60} @ARGV
' 7868190130M7522 5303914400F9211 9273338290F4010

Results:

7868190130M7522 5303914400F9211 9273338290F4010 -> 2

Example 2:

perl -E 'say "@ARGV -> ", 0+grep {/^...........(\d\d)..$/; $1>=60} @ARGV
' 1313579440F2036 2921522980M5644

Results:

1313579440F2036 2921522980M5644 -> 0

Maybe its simpler to just unpack, ignoring the first 11 characters: Example 1:

perl -E 'say "@ARGV -> ", 0+grep {($x)=unpack "x11A2"; $x>=60} @ARGV
' 7868190130M7522 5303914400F9211 9273338290F4010

Results:

7868190130M7522 5303914400F9211 9273338290F4010 -> 2

The full code is:

 1  # Perl weekly challenge 231
 2  # Task 2:  Senior Citizens
 3  #
 4  # See https://wlmb.github.io/2023/08/20/PWC231/#task-2-senior-citizens
 5  use v5.36;
 6  my $form="9999999999A1122";
 7  $form=~s/[9A2]/./g;     # Change form into a RE to obtain age. Change 9, A and 2 to any
 8  $form=~s/(1+)/($1)/;    # Capture  1's
 9  $form=~s/1/\\d/g;       # Change 1's to digits
10  $form=~s/^(.*)$/^$1\$/; # Add anchors
11  my $re=qr /$form/;      # convert to actual RE
12  say "@ARGV -> ", 0+grep {/^...........(\d\d)..$/||die "Wrong format: $_"; $1>=60} @ARGV;

Examples:

./ch-2.pl 7868190130M7522 5303914400F9211 9273338290F4010
./ch-2.pl 1313579440F2036 2921522980M5644

Results:

7868190130M7522 5303914400F9211 9273338290F4010 -> 2
1313579440F2036 2921522980M5644 -> 0
Written on August 20, 2023