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

Hello everyone. Some of you have been kind enough to work with me in chatter with this, but this is a little much to copy in chatter. I am trying to store the file names in an array, which I was surprisingly able to do, however when I try to get each file from the array and open it I am unable to. My suspicion is that I am using the wrong context, my error message is "Couldn't open file: ARRAY", which is why I think I have a list in a scalar context.

sub getFiles { my @fileNames = [ "manimp1.txt", "manimp2.txt" ]; for my $i (0..$#fileNames) { open (FILE, "<", $fileNames[$i]) or die "Couldnt open file: $ +fileNames[$i]\n"; while (<FILE>) { $count++; my @line_array = split (/\t/, $_); chomp(@line_array); my $key = shift(@line_array); my $aref = [@line_array]; $newPrices{$key} = $aref; } delete ($newPrices{'Part Num.'}); } }

I also tried

for my $file (@fileNames) { open (FILE, "<", $file) or die "Couldnt open file: $file\n";

This produced the same error. What I am attempting to do is build one hash with these two files, which was working fine when I was using user input to get the file names but since the file names will not change I wanted to bypass user input.

Sample of the data is as follows:
Part Num. Description Base Price Code 001051536 * (R/B 455632) 455632 001460 Ring 11.17 003034 Ball 0.82 018422 Nut 1.69 037506 Ring 3.25 041112023071 Seal Kit 402.98 041112030171 Engine Gasket Kit 611.32 041112030271 Seal Kit 1,035.86
I think I got all of the "problems" in here, double tabs, commas in the prices (who even does that), replacement parts, and non replaced parts.

Replies are listed 'Best First'.
Re: Opening an array of file names
by toolic (Bishop) on Apr 02, 2012 at 18:00 UTC
    Change:
    my @fileNames = [ "manimp1.txt", "manimp2.txt" ];

    to:

    my @fileNames = ( "manimp1.txt", "manimp2.txt" );

    The square brackets create a reference to an array. I think you just want to construct an array. See also:

      Yes, that did the trick, thank you.

Re: Opening an array of file names
by ww (Archbishop) on Apr 02, 2012 at 19:46 UTC
    toolic has identified the basic problem. These ramblings are for your consideration (in light of the self-characterization in your home node):

    You appear to be passing variables --$count and $newPrices{key} -- into getFiles() as arguments to the call. By doing it that way, your sub changes their values in main and in the sub. For example, if the first file has three lines and the second has four, and if the value of $count in main is 0 on entry to the sub, its value will be 7 when you return from the sub. That's probably a non-issue in the particular case, but it's a behavior of which you want to be aware.

    You've also written a sub with no explicit return which means the sub may do something you're not expecting, as explained in perlsub:

    "If no "return" is found and if the last statement is an expression, its value is returned."

    All in all, then, I commend a close reading of perlsub re return and also with special attention to the explanation of passing variables by reference.

    Update: clarifiation, p2, sentence 2 and fixed markup.

      Thanks for your input. I do know that a sub with no explicit return, it could create some unexpected return value. The subroutine is supposed to make changes to global hashes and I am not really relying on the return, so I am not too bothered by it. The  $count variable is a global in this case and I want to count all lines in the files. I made a few pretty drastic changes today, and I will continue to do that as I learn more stuff. One of the things I did was to reduce the number of global variables. I hope to eliminate global variables after I read what you suggested.

Re: Opening an array of file names
by jwkrahn (Abbot) on Apr 02, 2012 at 22:11 UTC
    sub getFiles { my @fileNames = [ "manimp1.txt", "manimp2.txt" ]; for my $i (0..$#fileNames) { open (FILE, "<", $fileNames[$i]) or die "Couldnt open file: $ +fileNames[$i]\n"; while (<FILE>) { $count++; my @line_array = split (/\t/, $_); chomp(@line_array); my $key = shift(@line_array); my $aref = [@line_array]; $newPrices{$key} = $aref; } delete ($newPrices{'Part Num.'}); } }

    That would probably be better as:

    sub getFiles { my @fileNames = ( 'manimp1.txt', 'manimp2.txt' ); for my $file ( @fileNames ) { open my $FILE, '<', $file or die "Couldnt open file: $file be +cause: $!"; while ( <$FILE> ) { chomp; my ( $key, @line_array ) = split /\t/; $newPrices{ $key } = \@line_array; } $count += $.; delete $newPrices{ 'Part Num.' }; } }

      Thanks for the input. The line:

      $newPrices{ $key } = \@line_array;

      is what I had originally, but my understanding is that is a reference to the array, and since the array changes when the next line is read, it made all the values in my hash the same, the last line of the last file. I understand that using  $newPrices{ $key } = [@line_array] creates a copy of the array. It is quite possible that I am mistaken since this is the first time I have really sat down with Perl.

        my ( $key, @line_array ) on the previous line creates a new variable each time through the loop so it is safe to use a reference to this variable.    If the variable was in a larger scope then what you describe would be a problem.

Re: Opening an array of file names
by Marshall (Canon) on Apr 02, 2012 at 18:57 UTC
    I am really lost in your subroutine.
    First of all, the name doesn't seem to match up with what it does.
    What is it that you are trying to do?
    More normal would be to call a subroutine to process each individual file - are the files related amongst each other somehow? Or are they independent?
    my @fileNames = ( "manimp1.txt", "manimp2.txt" ); foreach my $file (@fileNames) { processFile($file); } sub processFile { my $fileName = shift; open (....) ... what is supposed to happen here? }

      Well, yes the two files are related. They both contain parts of a single price file from one of our suppliers. My goal is to open each file and read it into a hash. What I am attempting to do is place each line in an array and perform some operations on the line before it goes into the hash. I have worked on it a little today but it is on my work VM and it is late so I don't feel like firing up my laptop to VPN. I will place the new script on my scratchpad tomorrow.