Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

find a string in an array of arrays

by jgatrell42 (Novice)
on Feb 06, 2008 at 21:44 UTC ( #666682=perlquestion: print w/replies, xml ) Need Help??

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

I have an array of arrays that looks like the following:
my @cdata = (["test1.txt", "Subject2", 200], ["test2.txt", "Subject2", 300], ["test3.txt", "Subject1", 600], ["test4.txt", "Subject4", 900], ["test5.txt", "Subject6", 200], );
Now I want to be able to look for the file name. Since the list can get rather long I decided maybe incorrectly to use grep.
my $SearchStr = "test2.txt"; my $GrepResult = grep(/$SearchStr/,@cdata);
Nothing is found. Now if I change the array to a simple array of file names it works great. That lead me to believe that the way I am referencing @Config is incorrect. I have not been able to get this to work. Thanks JGatrell

Replies are listed 'Best First'.
Re: find a string in an array of arrays
by Jenda (Abbot) on Feb 07, 2008 at 00:28 UTC

    There are four problems with your code. First the $_ in the grep() is assigned to an arrayref, you need to dereference the ref to get at the first element of the inner array of your AoA:

    my $GrepResult = grep($_->[0] =~ /$SearchStr/,@cdata);
    second you are executing the grep() in a scalar context .. in that context it will return the number of items matched, not the item(s) themselves:
    my ($GrepResult) = grep($_->[0] =~ /$SearchStr/,@cdata);
    third, the regexp would match even strings as 'not_the_test2.txt.gz':
    my ($GrepResult) = grep($_->[0] =~ /^$SearchStr$/,@cdata);
    that is you want (I believe) to find only the exact matches not the first file that contains the search string.
    Which leads to the last problem, the $SearchStr might contain some special characters ... actually it already does, the dot. The dot means "any character" within a regexp. So you would need
    my ($GrepResult) = grep($_->[0] =~ /^\Q$SearchStr\E$/,@cdata);
    to make sure such characters are escaped. In that case, it's easier though to get rid of the regexp completely:
    my ($GrepResult) = grep($_->[0] eq $SearchStr,@cdata);

    If you did need a regexp and were looking for something not exact there is one more thing to notice. qr//. If you do

    my ($GrepResult) = grep($_->[0] =~ /^$SearchStr$/,@cdata);
    then the regexp is compiled again for each item in @data. This could be expensive, especially if $SearchStr was really a regexp and was complex. In that case it's good to do something like
    my $regexp = qr/^$SearchStr$/; my ($GrepResult) = grep($_->[0] =~ $regexp,@cdata);
    This way the regexp is compiled just once and the search is quicker.

Re: find a string in an array of arrays
by Tanktalus (Canon) on Feb 06, 2008 at 22:01 UTC

    ITYM:

    my ($grepresult) = grep { $_->[0] eq $SearchStr } @cdata
    Or you could have $_->[0] =~ $SearchStr - but then your dot would match any character, which is probably not what you intended.

    Update: Added parens as per lodin's comment, as if I hadn't bitten myself twice already today with that oversight ;-)

      Beware of grep in scalar context. You need to use parentheses to create list context.

      Nowadays, i.e. with Perl 5.10, you don't have to specify how to match in the grep. Using the ~~ operator you can let $SearchStr handle that.

      my $SearchStr = 'foo.txt'; #my $SearchStr = qr/^foo_.*\.txt\z/i; #my $SearchStr = [ 'foo.txt', 'bar.txt' ]; my ($grepresult) = grep { $_->[0] ~~ $SearchStr } @cdata;

      lodin

      but then your dot would match any character

      You could do \Q...\E to quote the metacharacter.

      my ( $grepresult ) = grep { $_->[0] =~ m{\Q$SearchStr\E} } @cdata;

      Cheers,

      JohnGG

      Update: I also missed the scalar/list problem, parentheses added. lodin ++

Re: find a string in an array of arrays
by hipowls (Curate) on Feb 07, 2008 at 00:21 UTC

    The core module List::Util will be more efficient if there is a match since it will stop as soon as one is found.

    use List::Util qw(first); my $SearchStr = "test2.txt"; my $SearchResult = first { $_->[0] eq $SearchStr } @cdata; print "Found file: $SearchResult->[0]\n";

Re: find a string in an array of arrays
by ww (Archbishop) on Feb 07, 2008 at 02:35 UTC

    As I'm a bit puzzled your (larger) intent -- ie: why you would want to use a script for a job so easily done with ls text2.txt or dir text2.txt -- I'll guess you may wish to know the contents of the element rather than just a filename.

    If that's the case, here's a tiny, incremental step, building on the above, to print the full content of the element (annonymous array) containing test2.txt:

    print "Found \$SearchStr in \@cdata:  @{$GrepResult}\n";

    If, instead, you wish to store the information for further processing, you can substitute an appropriate construct to hold @{$GrepResult}.

    PS: your reference to "the way I am referencing @Config" is the kind of typo that can create confusion or lead to a sequence of off-track replies. Yes, I've inferred (correctly, one hopes) that you meant @cdata but sometimes typos or cut'n'paste errors can confound your hope of help. The preview button is best used both to the check formatting... and to proofread.

    ...of course, as anyone who's noted the number of "Update" notes in my posts will recognize, this is advice I need to practice more effectively, myself. :-)

    Update :-( and I still missed a typo I've now had to correct. ....aaargh!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://666682]
Approved by ww
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (2)
As of 2022-05-20 15:19 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Do you prefer to work remotely?



    Results (73 votes). Check out past polls.

    Notices?