awohld has asked for the wisdom of the Perl Monks concerning the following question:

I need to find the shortest (text length) element in an array.

For instance @array = qw( hello, superduper, hi )

I want to find "hi" since it's only two characters long. I need some direction on how to do this.
  • Comment on Finding the Shortest Element in an Array

Replies are listed 'Best First'.
Re: Finding the Shortest Element in an Array
by blokhead (Monsignor) on Oct 13, 2005 at 19:43 UTC
    Using my argmin subroutine from argmin & argmax, it's really easy:
    my @things = qw[ hello superduper hi ]; my $shortest = argmin { length } @things;
    In English, this reads: "return the element among @things that minimizes the length function."

    Alternatively, you could loop through the array, manually keeping a watermark of the shortest string seen so far and its index.

    blokhead

Re: Finding the Shortest Element in an Array
by friedo (Prior) on Oct 13, 2005 at 19:42 UTC
    Here's the long drawn-out way, but I'm sure some people will be along shortly with more elegant solutions:

    my @array = qw(hello superduper hi); my $shortest = $array[0]; for( @array ) { $shortest = $_ if length $_ < length $shortest; }
Re: Finding the Shortest Element in an Array
by borisz (Canon) on Oct 13, 2005 at 20:39 UTC
    use List::Util qw/reduce/; @array = qw( hello superduper hi ); print reduce { length( $a ) < length( $b ) ? $a : $b } @array;
    Boris
Re: Finding the Shortest Element in an Array
by holli (Abbot) on Oct 13, 2005 at 19:57 UTC
    my @a = qw(4444 22 1 22 333); my $shortest; my $min; for ( @a ) { my $l = length($_); if (not defined $min or $l<$min ) { $min=$l; $shortest=$_; } } print $shortest;
    Edit: looks like i was way to slow again.


    holli, /regexed monk/
Re: Finding the Shortest Element in an Array
by haoess (Curate) on Oct 13, 2005 at 20:07 UTC
    @array = qw( hello, superduper, hi )

    Maybe it's a mistake, but this creates a list containing three comma ending strings.

    For your algorithm you should have a look at the implementation of minmax in List::MoreUtils. It should be simple to adjust it to check for the length of a string. The documentation says:

    The minmax algorithm differs from a naive iteration over the list where each element is compared to two values being the so far calculated min and max value in that it only requires 3n/2 - 2 comparisons. Thus it is the most efficient possible algorithm.

    --Frank

      haoess,
      Actually, using List::Util's 'reduce' would be better. The minmax algorithm is doing more work then it needs because it is trying to identify both the min and the max where here only the min is desired. So in addition to List::Util being part of the core, it is also XS in most environments and implements the watermark algorithm which for this is much more efficient than 'minmax';

      Cheers - L~R

Re: Finding the Shortest Element in an Array
by Skeeve (Parson) on Oct 13, 2005 at 19:51 UTC

    I would simply loop over the elements comparing each stringlength with the current minimal length.

    While using all the bells and whistles with map and shift and sort and such, I think it's pretty overdone. Just as plain as this untested:

    use strict; use warnings; my @array = qw( hello, superduper, hi ); # You know that those commas are part of the strings!? my $shortest= $array[0]; my $shortest_length= length $shortest; for ($i= $#array; $i; --$i) { my $length= length $array[$i]; if ($length < $shortest_length) { $shortest_length= $length; $shortest= $array[$i]; } } print $shortest,"\n";

    Of course, one can shorten this, but you wanted a direction, not a "nice" solution...


    s$$([},&%#}/&/]+}%&{})*;#$&&s&&$^X.($'^"%]=\&(|?*{%
    +.+=%;.#_}\&"^"-+%*).}%:##%}={~=~:.")&e&&s""`$''`"e
Re: Finding the Shortest Element in an Array
by injunjoel (Priest) on Oct 13, 2005 at 19:40 UTC
    Greetings all,
    #!/usr/bin/perl -w use strict; my @array = qw(hello superduper hi); #our good friend the ST (aka: Schwartzian Transform) my $shortest = shift @{[ map{$_->[1]} sort{$a->[0] <=> $b->[0]} map{[length $_, $_]}@array ]}; print $shortest;
    Hope that helps. Here is the documentation on what is going on with the Schwartzian Transform.

    -InjunJoel
    "I do not feel obliged to believe that the same God who endowed us with sense, reason and intellect has intended us to forego their use." -Galileo
      injunjoel,
      I am not sure why you suggested sorting a list to find the shortest element. A watermark algorithm should be used since sorting does far more work then is necessary. I would have suggested List::Util's 'reduce' function or a hand rolled one as I demonstrated in my How A Function Becomes Higher Order tutorial.

      Cheers - L~R

        Perhaps sort was chosen because using sort is easy on the person writing the code. That was the first thing that came to my mind -- just sort the list based on length, but i see no reason to use a Schwartzian Transform here. This should suffice, and while it may take longer and use more memory, it sure looks neat:

        @array = sort { length($a) <=> length($b) } @array;
        Code like that reminds me of my days painting dorm rooms. My boss would tell me "Let the brush do the work, not you." And yes, that would include using List::Util, FWIW.

        jeffa

        L-LL-L--L-LL-L--L-LL-L--
        -R--R-RR-R--R-RR-R--R-RR
        B--B--B--B--B--B--B--B--
        H---H---H---H---H---H---
        (the triplet paradiddle with high-hat)
        
        Limbic~Region
        Looking back over my suggestion I guess the answer would be partly because sort seemed appropriate, as jeffa stated (nice sort suggestion by the way, much cleaner) and partly because of an idiosyncratic tendancy to over-use the ST.
        I've been writing more VB code than I would like to lately and I think this is just a subconscious backlash, my mind saying "Give me my programmatic flexibility back!!".

        -InjunJoel
        "I do not feel obliged to believe that the same God who endowed us with sense, reason and intellect has intended us to forego their use." -Galileo
Re: Finding the Shortest Element in an Array
by murugu (Curate) on Oct 14, 2005 at 03:01 UTC

    Here is my try

    @a=qw(adddddd bcdef deed superlative); ($shortest)=sort{length($a)<=>length($b)}@a; print $shortest;

    Regards,
    Murugesan Kandasamy.

Re: Finding the Shortest Element in an Array
by tphyahoo (Vicar) on Oct 14, 2005 at 10:54 UTC
    Well folks, here's a one-liner.

    print my $shortest = ( sort { length($a) <=> length($b) } qw( hello su +perduper hi ) )[0];
    outputs: hi.

    :)

Re: Finding the Shortest Element in an Array
by MidLifeXis (Monsignor) on Oct 14, 2005 at 17:24 UTC

    Since noone has (yet) used grep....

    sub shortest { my $shortest = length $_[0]; (grep { $shortest = length if($shortest > length); $shortest == length; }@_)[-1]); }

    --MidLifeXis

Re: Finding the Shortest Element in an Array
by niraj_sheth (Initiate) on Oct 15, 2005 at 16:51 UTC
    How about .. my $first = (sort {length($a) <=> length($b)} @array)[0];