PWC #250

PWC 250

Disclaimer on earlier "Perl 4" attempts

In my previous challenges, I often mentioned sticking to Perl 4 syntax. I did not actually have Perl 4, so could not test on that platform. 

Recently, I did manage to find an old MS-DOS executable of Perl 4.019 that I can run in DOSBOX.

I quickly found that my "Perl 4" answers to earlier challenges will not run in Perl 4.

Particularly, my habit of using "local *xxx = sub { ...};" to create a localized sub will not work on Perl 4. Firstly, the "local" keyword must be used with a bracketed list of arguments, as local (*x, ...). The statement form "local *x," gives a syntax error. Secondly, the sub keyword cannot appear on the right-hand-side of an assignment. Syntax error again even with "local (*x)=sub {..};" .

Looks like this facility to assign a sub to a local glob only became available in Perl 5. In Perl 4, looks like subroutines always had to be global or package-level in scope.

If I get time, I will update my earlier blog posts to add this disclaimer.

Challenge 1 (Smallest Index)

We are given a list of integers ints say. We are asked to return the smallest index i such that:

(i % 10) == ints[i]

The indices start from 0, as in Perl.

If there is no index matching the condition, we return -1.

This is a quick and easy task in Perl 5. Could be a one-liner, but I opt for a longer subroutine.

Here is the key snippet:

my $smallest_index = sub {
    my $retval=
    (sort {$a<=>$b}
    (grep {($_ % 10) == ($_[$_])} (0 .. $#_))
    )[0];
    defined($retval) ? $retval : -1;
};

I use grep to extract the indices of ints that match the condition, sort these in ascending order, and then return the first (minimum) element. If there is no such element because the grep returned an empty list, I return -1.

Challenge 2 (Alphanumeric string value)

We are given a list of strings. For each string in the list, we evaluate a number using the following rule. 

  • If the string can be evaluated as a base-10 number (like "4" or "000"), the number is simply this number (4 for "4" and 0 for "000").
  • Otherwise, the number is the string length.

We return the highest of the numbers derived from each input list element.

Again, a quick and easy task in Perl 5. Potential one-liner for sure, but I prefer to stick to a longer subroutine. Here it is:

local *alphanumeric_string_value = sub {
    local *alphanumeric_string_value = sub {
        ($_[0] =~ /^[0-9]+$/) ?
        (0+$_[0]) :
        length($_[0]);
    };

    (sort {$b<=>$a}
    (map {&alphanumeric_string_value($_)} @_)) [0];
};

I use dynamic (local) scope to redefine the alphanumeric_string_value sub inside itself. The inner version applies to a scalar treated as a string, while the outer version loops over a list, calling the inner version for each element; and then returning the maximum.

The inner version checks the string to see if it consists only of digits. If it does, then we evaluate it numerically by adding it to 0, otherwise we take the length of the string. 

This only recognizes positive integers as numeric, "-1.23" or "4.5" would be treated as strings.This matches the spec which indicates that only strings consisting of digits only should be treated as numbers.

Comments

Popular posts from this blog

PWC 227

PWC 234

PWC 249