PWC 229
PWC 229
Challenge 1 (Lexicographic Order)
We are given a list of strings. We are asked to count the number of elements that are strings whose constituent characters are not all either in weakly monotonically ascending lexicographic order or weakly monotonically descending lexicographic order (i.e., component strings whose characters are NOT either all in ascending or all in descending dictionary order).
I use a sub-subroutine &is_sorted that checks if each string is sorted. If the string has less than 3 elements, then it is automatically sorted. Otherwise, we check the order of the first 2 elements, say either element 1 is (lexical) less than or equal to (le) element 2, or element 1 is greater than or equal to (ge) element 2. We proceed to loop through the remaining elements to verify that they have the same ordering relationship (le or ge) as the first two.
In the main part of the subroutine, we call &is_sorted on each string in the array (map), then extract the zeroes (not sorted) in the resulting array (grep), and return the length of the array of extracted zeros (scalar).
Here is the subroutine:
#-- helper subroutine
local *is_sorted = sub {
my ($str)=@_;
(length($str) < 3) && (return 1);
my $op;
( substr($str,0,1) le substr($str,1,1) ) ?
($op = 'le') : ($op = 'ge');
INSTRING: for my $x (2 .. (length($str)-1)) {
my $test = ('\''. substr($str,$x-1,1) .'\' '. $op .' \''. substr($str,$x,1).'\'');
unless (eval($test)) {
return 0;
last INSTRING;
}
}
1;
};
#-- main trunk of subroutine
my @str = @_;
scalar grep /0/, map {&is_sorted($str[$_])} 0 .. $#str;
}
Challenge 2 (Two out of three)
We are given three arrays (presumably 3 arrayrefs in Perl 5). We are asked to extract a list of items that are elements of at least two out of the three arrays.
My solution is probably not the most efficient. I use three hashes to record membership in each of the three arrays. Then I use another hash %two_out_of_three to count elements in at least two out of three arrays. I loop through the keys of the membership hashes for the first two arrays in the input, recording in %two_out_of_three which of the keys also exists in one or both of the other membership hashes. Finally, we return the keys of %two_out_of_three.
Here is the subroutine:
#-- helper sub sub
local *in_arry = sub {
local @in_arry=@_;
local %in_arry;
map {
$in_arry{$_}=1;
} @in_arry;
%in_arry;
};
#-- main trunk of sub
my ($ra1, $ra2, $ra3)=@_;
my %rh1 = &in_arry($ra1->@*);
my %rh2 = &in_arry($ra2->@*);
my %rh3 = &in_arry($ra3->@*);
my %two_out_of_three;
map {( (exists $rh2{$_}) || (exists $rh3{$_}) ) &&
($two_out_of_three{$_}=1);} keys %rh1;
map {( (exists $rh1{$_}) || (exists $rh3{$_}) ) &&
($two_out_of_three{$_}=1);} keys %rh2;
keys %two_out_of_three;
}
I probably should have called the membership hashes %hash1, %hash2, etc., rather than %rh1, %rh2, etc. since I usually use the rh prefix as Hungarian notation to signify a hashref. I'll leave this minor inconsistency.
Comments