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

Hi, I have an array holding a mixture of numbers and single letter strings (e.g., {1, 2, 4, 5, A, B, C} ). I am using the following sub-function to search for a given letter (e.g., ‘Q’) but it only works when I search for the numbers. When I search for any string, I get the index corresponding to the letter ‘A’ only. Why is this?
sub find { my($var, @array); $var =$_[0]; @array=@_[1..$#_];; my $index = 0; ++$index until $array[$index] == $var or $index > $#array; #print "@array\n"; #print "$array[$index]\n"; return $index; } $result = &find (‘Q', @fsg); print "$result\n $fsg[$result]\n”; # returns index for the first non- +integer regardless of what that item is $result = &find (‘2', @fsg); print "$result\n $fsg[$result]\n”; # returns correct index $result = &find (‘102', @fsg); print "$result\n $fsg[$result]\n”; # returns the length as the array a +s the index - which is the value I check to see if a match occurred o +r not.

Replies are listed 'Best First'.
Re: Searching mixed array?
by Corion (Patriarch) on Apr 26, 2011 at 21:02 UTC

    Your code as posted can't run because you're using some kind of fancy quotes that Perl does not support:

    &find (‘Q', @fsg)

    If you used the warnings pragma, Perl would have told you that you're using the wrong operator for string comparisons. See perlop about eq and == and the difference between the two.

    Also, if you plan on doing (much) more than one search, using a hash is likely faster:

    sub find { my ($needle,@hay) = @_; my $position = 1; my %haystack = map { $_ => $position++ } @hay; return $haystack{ $needle } };

    If you look at List::Utils, there is the first subroutine, that also does what your find() subroutine does.

Re: Searching mixed array?
by kennethk (Abbot) on Apr 26, 2011 at 20:58 UTC
    You need to change

    ++$index until $array[$index] == $var or $index > $#array;

    to

    ++$index until $array[$index] eq $var or $index > $#array;

    Perl has both a string equality operator eq and a numeric equality operator ==. Integers will be stringwise equivalent to themselves, but strings evaluate to zero in numeric context (unless they look like numbers), so nearly all strings are numerically equivalent in Perl. See Equality Operators in perlop for details.

Re: Searching mixed array?
by toolic (Bishop) on Apr 26, 2011 at 21:07 UTC
    See also List::MoreUtils::firstidx
    use warnings; use strict; use List::MoreUtils qw(firstidx); my @fsg = (1, 2, 4, 5, qw(A B C)); printf "item with index %i in list is B\n", firstidx { $_ eq 'B' } @fs +g; printf "item with index %i in list is 2\n", firstidx { $_ eq 2 } @fsg; __END__ item with index 5 in list is B item with index 1 in list is 2
    use strict and warnings
      Thank you very much everyone for your answers. I’ve just begun learning Perl after many years of using compiled languages such as C/C++. Although I seem to have made an elementary mistake in this case, I am very impressed at how quickly one can become productive with Perl. I am using it to do some statistical analysis in support of a few Natural Language Processing algorithms I am developing.
        If you are performing more than very basic statistical analyses, you should take a look at Bundle::Math::Statistics and the modules it contains - it may save you a lot of effort.