gnu@perl has asked for the wisdom of the Perl Monks concerning the following question:

In the follow code (in progress), I have two arrays, @toget and @sourcefiles. @toget contains a list of base file names I need to find (they might have a different extension) and @sourcefiles is a listing of all the files I wish to look through.

What I am wondering is if I can match a regex against an array to see if there is an element that matches, if so, I want to retrieve that element.

For example, can I do this:  if (@sourcefiles =~ /.*P.*\.0912\.ama\.gz/) { ..code.. };

I am trying to avoid having to do a File::Find on every pattern I'm looking for or having to iterate through the arrays to compare @toget to see if each element is in @sourcefiles.

Any ideas are appreciated.

TIA, Chad.

#!/usr/local/bin/perl -w use strict; use File::Find; use Data::Dumper; my $file = "/u90/gvc_archive/ama_recover/chad.lst"; my $startDir = "u90/gvc_archive/ama_recover"; my $destDir = "$startDir/4tych"; my @toget; my @sourcefiles; chdir $startDir; open(FILES,"<$file"); for (<FILES>){ push(@toget,$_); } find(\&pushsources,"."); sub pushsources { my $file = $File::Find::name; push(@sourcefiles,$file); }

Replies are listed 'Best First'.
Re: matching regex on an array element w/o looping the array
by sauoq (Abbot) on Oct 03, 2002 at 15:11 UTC
    For example, can I do this: if (@sourcefiles =~ /.*P.*\.0912\.ama\.gz/) { ..code.. };
    if (grep /.*P.*\.0912\.ama\.gz/, @sourcefiles) { # ... code ... }

    That isn't very efficient if you need the matches later though. It may well make more sense for you to save the list returned by grep.

    my @matched = grep /.*P.*\.0912\.ama\.gz/, @sourcefiles; if (@matched) { # ... code ... }

    By the way, this doesn't do it without looping the array. The grep() just hides the loop.

    -sauoq
    "My two cents aren't worth a dime.";
    
Re: matching regex on an array element w/o looping the array
by antifun (Sexton) on Oct 03, 2002 at 15:32 UTC
    If you're going to be doing something with each element the following 'for' idiom is useful:
    for (grep /.*P.*\.0912\.ama\.gz/, @sourcefiles) { # $_ contains each matching name }
    As sauoq pointed out, though, this does iterate over the list. It's hard to search through a list without iterating :) But grep is your friend. Learn it, love it.
    ---
    "I hate it when I think myself into a corner."
    Matt Mitchell
Re: matching regex on an array element w/o looping the array
by helgi (Hermit) on Oct 03, 2002 at 16:27 UTC
    Here's one way:
    use warnings; use strict; use File::Find; my $dir = '/full/path'; my %fullpath; my @toget = qw/foo goo moo/; #my $pattern = join "|",@words; # bad mistake on my part my $pattern = join "|",@toget; find sub { $fullpath{$_} = $File::Find::name if -f $File::Find::name; +},$dir; for (keys %fullpath) { print $fullpath{$_}; if (/($pattern)/i) { print "\t$1\n" } else {print "\tNO MATCH\n";} }

    -- Regards,
    Helgi Briem
    helgi AT decode DOT is

      Thanks for your help, you kind of spurred me onto an idea. Here's what I did and it worked great.
      #!/usr/local/bin/perl -w use strict; use File::Find; use Data::Dumper; my $file = "/u90/gvc_archive/ama_recover/chad.lst"; my $startDir = "u90/gvc_archive/ama_recover"; my $destDir = "$startDir/4tych"; my @toget; my %sourcefiles; my @foundfiles; chdir $startDir; open(FILES,"<$file"); find(\&pushsources,"."); for (<FILES>){ s/ *$//; chomp; print "Checking $_\n"; my $file = $sourcefiles{"$_"}; print "\t $file \n" if ($file); } sub pushsources { s/\.gz$//; chomp; $sourcefiles{$_}=$File::Find::name ; }
      Thanks, but I'm a little confused. What is @words used for?
        I'm most awfully sorry. @words was leftover from an earlier version. I changed the name to @toget to match yours, but forgot to change it in both places. That should teach me not to fix things after cutting and pasting.

        -- Regards,
        Helgi Briem
        helgi AT decode DOT is