All,
Intrepid asked in the CB for a piece of code that would satisfy the following requirements:
- Identify values in a list with the minimum length
- Identify the maximum string value in the resulting list
- Identify a random value from the resulting list
These have been generalized a bit as hashref keys were involved, but I provided the following straightforward solution:
my @min_keys = sort { length($a) <=> length($b) || $a cmp $b } keys %$
+hashref;
my $min = length $min_keys[0];
for ( 1 .. $#min_keys ) {
if ( length $min_keys[$_] != $min ) {
splice @min_keys, $_;
last;
}
}
# maxstr & random
print join "\t", $min_keys[-1], $min_keys[ rand @min_keys ];
There was a follow on discussion about how this could be done efficiently. While
some were interested in a general solution that may be incorporated into
List::Util, I felt a variation of the watermark algorithm was all that was needed to satisfy all the requirements in a single pass:
my @list = qw(zero one two three four five six seven eight nine ten el
+even twelve);
my ($maxstr, $random) = find_shortest( @list );
print join "\t", $maxstr, $random;
sub find_shortest {
my ($pos, $len, $maxstr, @min) = (0, undef, '', 0, undef);
my %dispatch = (
-1 => sub {
($len, $pos) = (length($_), 0);
($min[$pos], $maxstr) = ($_, $_);
},
0 => sub {
$min[++$pos] = $_;
$maxstr = $_ if $_ gt $maxstr;
},
1 => sub { return },
);
for ( @_ ) {
if ( ! defined $len ) {
$len = length();
($min[$pos], $maxstr) = ($_, $_);
next;
}
$dispatch{ length($_) <=> $len }->();
}
return ($maxstr, (@min[0..$pos])[rand $pos]);
}
There are still ways to improve on it, but I thought it was neat and only required a minimal amount of extra effort. How could you improve (keeping the original 3 requirements in mind)?
Cheers - L~R