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

I am working on a script and cannot figure out how to get this last part working.
I have two arrays that I need to compare and then do something with the comparison.


The first array is a list of files. @update
The second array is a list of directories.@prod


I created a hash out of the second array (directories). Now the comonality between the two arrays is that the first 4 characters of the file array will match the name of the directories. I have been trying to write a loop that would look at the first 4 characters of each item in the file array and compare it to each item in the directory array. When it finds an item that matches it is to copy this item to the corresponding folder (the folder who's name matches the first 4 character of the file name).

So far as stated I have a list of the arrays and then turned the array of directories into a hash, then come my problem. Comparing the array of files to the hash is not working as expected. I know I am using "if" in a loop with a hash, is this incorrect? Here is what I have tried:

So this opens the array of directories and assignes them to a hash.


opendir (DIR2,"$to_dir") || die "Cannot open directory $!";
@prod=readdir(DIR2);
closedir(DIR2);
@prod = sort @prod;
foreach $h(@prod){$seen{$h} = 1}



This creates an array of files and then incorrectly try to compare the first 4 items of the array to match an item in the hash and then copy it. I can figure out the copy part, but hash parsing escapes me.


opendir(DIR,"$from_dir") || die "Cannot open directory $!";
@update=readdir(DIR);
closedir(DIR);

@update= sort @update;

foreach $i(@update){
if (/^\d{4}/ eq $seen{$h}){
copy($i,$to_dir)
}



Any pointers would be greatly appreciated.

Replies are listed 'Best First'.
Re: Compare and copy array values
by jwkrahn (Abbot) on Mar 19, 2008 at 19:57 UTC

    It sounds like you need something like this:

    my %file_lookup; for my $file ( @update ) { push @{ $file_lookup{ substr( $file, 0, 4 ) } }, $file; } for my $dir ( @prod ) { next unless exists $file_lookup{ $dir }; for my $file ( @{ $file_lookup{ $dir } } ) { copy( $file, "$dir/$file" ) or warn "Cannot copy '$file' to '$ +dir/$file' $!" } }
      If the variables are declared a the beginning of the script do I need to use "my" when referencing them further down in the script?

        If you do re-declare them, they will override the earlier one.

        my $crap =1; print "crap is $crap\n"; my $crap =2; print "crap is $crap\n";
        produces
        crap is 1 crap is 2

        If you include use warnings; at the beginning of the scripts, you will get "my" variable $crap masks earlier declaration in same scope at crap.pl line 8. which can be very useful!

        Just keep in mind that it checks in the same scope. That means you can re-declare the same variable name inside a loop and Perl will silently accept it.

        Enjoy
        ~ Michael

        No, you don't.

        But loop variables should be declared in the loop construct:

        foreach my $item (@list) { }
        or (means the same)
        for my $item (@list) { }
Re: Compare and copy array values
by olus (Curate) on Mar 19, 2008 at 19:47 UTC

    If I understand correctly, the keys of the hash %seen will be the directory names, so what you need to compare is the filename to those hash keys. What you are doing now is compare the filename to the value of one hash key.

    what you want is to check if the result of the pattern match is a directory that has been seen.

    foreach $i(@update){ $i =~ /^(\d{4})/; # match and grab into $1 the first four digit +s if($seen{$1} == 1){ # test if the dir has been seen copy($i,$to_dir); } }
      When it finds an item that matches it is to copy this item to the corresponding folder (the folder who's name matches the first 4 character of the file name).

      Sounds like your desired folder is a subfolder of $to_dir. Instead of

      copy($i,$to_dir);
      assign that four-character string to a variable so you can
      1. check for the existence of a subfolder with that name, and
      2. copy the file to that subfolder.

      The capture variable $1 holds the string you want if the match succeeded, otherwise it may hold something left over from an earlier successful match. So don't use $1. Say

      FILE: for my $file (@update) { my $first_4_chars = substr($file, 0, 4); next FILE if not $seen{$first_4_chars}; copy($file, "$to_dir/$first_4_chars"); }

      Oh, and please

      use strict; use warnings;