This is a small sub that returns the length of the longest string value in a hashref. Arg must be passed by ref. Any additional arg causes it to look for longest key instead.


It's lovely to collaboratively code with fellow Monks. Last localtime-night in the cb Brer' broquaint and I wrote this subroutine which I've decided to name max_strl (a kind of C-ish name for a Perl identifier, granted).

Usage:

Pass the first argument/parameter as a hash reference. If any additional argument is passed the function will return the length of the longest key instead of the length of the longest value.


Update: Wed Aug 20 2003 23:08 UTC

Incorporated diotalevi's suggestion so that we can pass a blessed object that is a (isa()) hashref, as well.
# last mod: Wed Aug 20 2003 23:08 UTC # by [Intrepid], with quality tweaking by [broquaint] ;-) sub max_strl { UNIVERSAL::isa( (my $h = shift) , 'HASH') or die "Must pass a hashref!\n"; my $ml = 0; length > $ml and $ml = length for ( @_ ? keys %$h : values %$h ); return $ml; }

Applications:

Although it's a very short piece of code (made even more concise due to broquaint's economy of style), this is IMHO a broadly useful bit. One general area where it is likely to be helpful concerns those times in which we are trying to exercize a little more fine-grained control over spacing in our screen real-estate. Something a little more precise than just sprinkling our output format with TABs ...

For (a dumb) example, to pretty-printout a hash of varying-length items like this, with stuff on both front and behind:

#!/usr/bin/env perl use strict; use warnings; $\ = "\n"; my $i = 'A'; my(%hash) = map(($i++, $_), split(/:/, $ENV{'PATH'}, 0)); my $maxl = max_strl(\%hash) + 5; my $format1 = "PathEle %3s%${maxl}s% 10u Kb used"; foreach (sort keys %hash) { my $use_of_disk = "du -ks $hash{$_}"; printf "$format1\n", $_, $hash{$_}, (split /\s+/,`$use_of_disk`)[0 +]; } exit 0;

Using max_strl with printf() is just the start. Your imagination is the only limit! {grin}.

Replies are listed 'Best First'.
Re: max_strl - Get length of longest string in a hash
by diotalevi (Canon) on Aug 20, 2003 at 22:12 UTC

    It'd be nicer if you did an isa() check for 'HASH' rather than your ref() check. Currently you don't allow me to pass in a blessed hash.

Re: max_strl - Get length of longest string in a hash
by DrHyde (Prior) on Aug 21, 2003 at 09:43 UTC
    Rather than iterating through the hash each time you need to figure out the longest value, I'd tie the hash such that it kept track of the longest whenever the contents change. Then you could do:
    $maxlength = length(tied(%hash)->longestvalue());
    or something like that.
      Hmmm... and how would that be able to take care of:

      $hash{a} = '1234567'; $hash{b} = '12345678'; $hash{c} = '123456789'; delete $hash{c};
      in other words: when the longest is deleted, which one is then the longest? You would need to set a flag that would force a re-scan on delete of the longest.

      Implementation details, maybe, but also maybe a can of worms you don't want to get into... ;-)

      Liz

        Like this . Pretty trivial really, once you've figured out what all the possibilities are - and writing the tests first really helps. It copes with items being deleted and with items being changed, only rescanning when absolutely necessary.

        I shall now cross all my fingers and toes and hope there's no bugs :-)

Re: max_strl - Get length of longest string in a hash
by Aristotle (Chancellor) on Aug 24, 2003 at 06:12 UTC
    Hmm?
    use List::Util qw(max); my $max_len_keys = max map length, keys %hash; my $max_len_vals = max map length, values %hash;
    In cases like this where I specifically expect a "ref to X" I might even consider using a prototype (in this case, \%;$), then you can get rid of your own type checking and it will work regardless of any magic attached to whatever is passed in.

    Makeshifts last the longest.