Reputation: 105
Is it possible to create different named arrays while looping in Perl? What I need to do is open some files from @ARGV
and put their data in separate arrays in one loop, for example: 1.txt
in @first_array
, 2.txt
in @second_array
and etc. Is it possible and if yes, what would be the best approach?
EDIT:
I think I'm getting closer, since Data::Dumper
shows a correct structure of what I need, but it doesn't show the values of the files, instead, it shows this:
$VAR1 = {
'skai.txt' => [
\*{'::$fh'},
$VAR1->{'skai.txt'}[0],
$VAR1->{'skai.txt'}[0],
$VAR1->{'skai.txt'}[0]
],
'numb.txt' => [
\*{'::$fh'},
$VAR1->{'numb.txt'}[0],
$VAR1->{'numb.txt'}[0],
$VAR1->{'numb.txt'}[0]
]
};
Each file consists of 4 numbers. My code looks like this:
use strict;
use warnings;
use Data::Dumper;
my $data = {};
foreach my $arg(@ARGV){
if(open(my $fh, $arg)){
$data->{$arg}=[];
while(<$fh>){
chomp;
push @{$data->{$arg}}, $fh;
}
close($fh);
}
}
print Dumper $data;
What is the meaning of \*{'::$fh'}
?
Upvotes: 1
Views: 90
Reputation: 69224
This is the strange part of your code:
push @{$data->{$arg}}, $fh;
$fh
is the filehandle. That's why you're getting that output. Each time around the loop, you're adding exactly the same value (the filehandle) to your data structure.
'skai.txt' => [
\*{'::$fh'},
$VAR1->{'skai.txt'}[0],
$VAR1->{'skai.txt'}[0],
$VAR1->{'skai.txt'}[0]
],
The first value (\*{'::$fh'}
) is just Data::Dumper's slightly over-complicated way of saying "a reference to the filehandle that is stored in $fh
". The three subsequent values are Data::Dumper saying "this is a value that already appears in this data structure, so instead of writing the value out again, I'll just show you a reference to the existing value".
I think that if you change that line to:
push @{$data->{$arg}}, $_;
Then you'll get something a lot closer to what you wanted.
Upvotes: 2
Reputation: 4602
It sounds like you don't really need the individual arrays to be named @first_array
, @second_array
, etc. You just want to keep them separate.
In that case, why not just have an array of arrays? Like so:
my @array_of_arrays;
for my $f (@ARGV) {
my @array = load_file($f);
push @array_of_arrays, \@array;
}
Note: load_file
is just a placeholder for some function you presumably have to read a file into an array.
Then later on...
array_of_arrays[0][0] * array_of_arrays[1][0] * ... * array_of_arrays[$N][0]
Update: You need to pass a reference to @array
to the push
function, rather than just @array
. Otherwise, push
will create a flattened array containing all of the elements of each individual array. Thanks to @Garo and @mob for pointing this out.
Upvotes: 2
Reputation: 1510
If I understand your question correctly, what you should use is arrayreferences inside a hash, hashref, array or arrayref.
Below is how i would do it (a hashref of arrayrefs):
my $data={}; #a hashref where all data will end up
foreach my $currentfile (@ARGV){
open (my $filehandle ,$currentfile);
$data->{$currentfile}=[]; #a empty arrayref inside the hashref for every file
while(<$fh>) {
push @{$data->{$currentfile}}; #add lines to the arrayref
}
close $filehandle;
}
Result: all data will be available in the form $data->{FILENAME}->[LINENUMBER COUNTING FROM 0]
.
Example: line 7 of file "foo.txt" will now be in $data->{foo.txt}->[6]
Depending on your actual purpose an array or arrayref might be a better choice then a hashref (If you don't care about the filenames but care about which number of argument they are in @ARGV
). But this is not entirely clear in your question
Upvotes: 1