http://qs1969.pair.com?node_id=195423

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

I read through grep, but the doc doesnt seem to indicate whether or not a situation where grep matches nothing results as undef or an emptry string. My code:

my $vndr_key = (grep { $args->{desc} =~ m/$_/i } keys %vendors)[0]; if ($vndr_key ne '') { #do something } else { #do something else }

I'm getting an error Use of uninitialized value in string ne when the grep finds nothing. Would a if (!$vndr_key) be a better fit? And if so, I'd still like to understand just what grep is returning.

Thanks -c

Replies are listed 'Best First'.
Re: no grep match returns undefined?
by kvale (Monsignor) on Sep 05, 2002 at 16:18 UTC
    grep returns an array of matched elements. So if there are no matches, then the first array element is undefined. A better way would be
    my @vndr_keys = grep { $args->{desc} =~ m/$_/i } keys %vendors; if (@vndr_keys) { #do something } else { #do something else }
    -Mark
      grep returns an array of matched elements

      Actually it returns a list of matched elements.

      The difference can be important.

      --
      <http://www.dave.org.uk>

      "The first rule of Perl club is you do not talk about Perl club."
      -- Chip Salzenberg

•Re: no grep match returns undefined?
by merlyn (Sage) on Sep 05, 2002 at 17:04 UTC
    When grep can't find anything, it returns an empty list in a list context, or 0 in a scalar context. Since the next operation is a list slice, the list slice is providing list context to grep, and thus gets an empty list. You're then taking the 0'th element of an empty list, which is defined to be undef, because whenever you access "beyond the end of the array", you get undef. This is not a "special case" for grep.

    Really, it's a matter of understanding each step, and is desk-checkable before running. Don't throw code together. Build it.

    -- Randal L. Schwartz, Perl hacker

Re: no grep match returns undefined?
by thelenm (Vicar) on Sep 05, 2002 at 16:16 UTC
    In list context, grep will return an empty list if no matching elements were found. What you're doing is trying to access the 0th first element of an empty list, which results in undef.

    -- Mike

    --
    just,my${.02}

Re: no grep match returns undefined?
by bart (Canon) on Sep 05, 2002 at 19:01 UTC
    my $vndr_key = (grep { $args->{desc} =~ m/$_/i } keys %vendors)[0]; if ($vndr_key ne '') { #do something } else { #do something else }
    I'm getting an error Use of uninitialized value in string ne when the grep finds nothing.
    I'm sure you already know what causes the warning. What others haven't stressed, is how you can simplify your code. You're really doing too much work.
    my $vndr_key_count = grep { $args->{desc} =~ m/$_/i } keys %vendors; if ($vndr_key_count) { #do something } else { #do something else }
    grep() in scalar context returns the number of matches. With no matches, that is zero. And zero is false. There's no need to compare it to another false value, they needn't be the same anyway.

    Hmm... what is it with you Perl newbies and that grep { $str =~ /$_/ } LIST thing? This will compile the regex for every loop. That will be rather slow. If you don't want pattern matches, don't use a regex, not like this: use index(). And if you do want it, this will be faster:

    my $re = join '|', keys %vendors; my $vndr_key_found = $args->{desc} =~ /$re/; if($vndr_key_found) { ... } else { ... }
    It's simpler. It's very likely a lot faster.
      You can get rid of both temporary variables that way too. Step 1:
      my $re = join '|', keys %vendors; if($args->{desc} =~ /$re/) { ... } else { ... }
      Step 2: if($args->{desc} =~ /@{[join '|', keys %vendors]}/) { ... } else { ... } Depending on your Perl prowess you may or may not find step 2 readable.

      Makeshifts last the longest.