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

Still not understanding grep and array of arrays... I wrote a the test listed below to figure this out and I am having no luck. What am I missing? Could some please give me an example of the working command thenexplain how it works. I can get grep to work in a normal array, but not when I move to array of arrays. Is grep not the best way to perform a substring seach and return the array or an index to the array that matches? I left in some of the things I have tried.
#!/usr/bin/perl use strict; my @test2 = (["KATE","1001"], ["XERXES","1002"], ["LARRY","1003"], ["TEDDY","1004"], ["DANA","1005"], ["SHERRY","1006"]); #my ($grepnames) = grep{$_ eq "ER"} @test2; #my ($grepnames) = grep(/"ER"/, @test2); my @grepnames = grep {$_->[0] eq "ER"} @test2; print ("@grepnames\n");
Thanks Jon

Replies are listed 'Best First'.
Re: substring search in an array of arrays
by Fletch (Bishop) on Feb 14, 2008 at 21:57 UTC
    • grep returns the elements for which the test is true, so in your case you'd get the matching arrayrefs
    • of course you have no arrayrefs in @test2 with ER as their first element
    • perhaps you meant $_->[0] =~ /ER/ as the test?
    • Then again that'd just give you two items ([ "XERXES", "1002"] and [ "SHERRY", "1006" ]) in @grepnames
    • so you'd probably want to iterate over the indexen of your array instead if that's what you're really interested in (i.e my @name_indexen = grep $test2[ $_ ]->[0] =~ /ER/, 0..$#test2;)
    • Of course if you're really interested in the names themselves then what you really want is probably going to wind up some combination with map and you'll want to search for the term "schwartzian transform"
    • The cake is a lie.
      The cake is a lie.
      The cake is a lie.

Re: substring search in an array of arrays
by toolic (Bishop) on Feb 14, 2008 at 23:00 UTC
    Others have provided examples using grep. Here is a non-grep example.
    #!/usr/bin/env perl use warnings; use strict; my @test2 = ( ["KATE" , "1001"], ["XERXES" , "1002"], ["LARRY" , "1003"], ["TEDDY" , "1004"], ["DANA" , "1005"], ["SHERRY" , "1006"] ); my @grepnames; for my $aref (@test2) { push @grepnames, @$aref[0] if (@$aref[0] =~ /ER/); } print "@grepnames\n";

    prints:

    XERXES SHERRY
    A good resource for this type of task is perldsc.
Re: substring search in an array of arrays
by lackita (Sexton) on Feb 14, 2008 at 23:02 UTC

    One useful thing to think about with grep is what it will look like as a loop.

    my @grepnames = grep {/"ER"/} @test2;
    Is the same as
    my @grepnames; for my $test2item (@test2) { push @grepnames,$test2item if $test2item =~ /"ER"/; }
    After looking at it in this format, I believe it's easier to notice that we're trying to match each item against an arrayref instead of the first element in the array.

    Another thing I noticed is I think you're confused on how the eq operator works. This operator sees if the string before the operator is exactly the same as the string after the operator. So the only thing that would evaluate to true in the comparison is "ER" eq "ER".

    The last thing I noticed is that regexps treat quote characters as literal quote characters instead of designating a string. So "XERXES" wouldn't match the pattern /"ER"/ but 'X"ER"XES' would.

Re: substring search in an array of arrays
by BrowserUk (Patriarch) on Feb 14, 2008 at 22:30 UTC

    Close:

    @test2 = (["KATE","1001"], ["XERXES","1002"], ["LARRY","1003"], ["TEDDY","1004"], ["DANA","1005"], ["SHERRY","1006"]);; @grepnames = grep {$_->[0] =~ "ER"} @test2;; print "@$_" for @grepnames;; XERXES 1002 SHERRY 1006

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

      "ER" is misleading. It implies ER is text while it's really a regex. Use /ER/ instead.

      Don't pretend the first argument of split is text.
      Don't pretend the RHS of =~ is text.

      my @grepnames = grep { $_->[0] =~ /ER/ } @test2; print(join(', ', @$_), "\n") for @grepnames;

      Update: Fixed LHS to say RHS.