1

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'}?

2
  • Do you really need the arrays to be named first_array, second_array, etc? Or do you just want to make sure each file gets loaded into a separate array? Commented Mar 20, 2019 at 23:18
  • Not sure, what I really need to do is to later access elements from different arrays with the same indexes(I need to multiply first_array[0] with second_array[0], first_array[1] with second_array[1] and etc.) Commented Mar 20, 2019 at 23:37

3 Answers 3

2

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Incorrect, push @array_of_arrays, @array will just add all values in @array to @array_of_arrays. The result here will be one large array and not an array of arrays
@Garo Not according to Data::Dumper. That's weird. I think you're actually correct, but now I can't explain why Data::Dumper shows an array of arrays.
Data::Dumper would show an array of arrays if the return value of load_file was an array reference, and every assignment to @array made it an array with a single array reference element.
2

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.

Comments

1

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

2 Comments

Thanks, your answer helped a lot. I edited my question after adding Data Dumper, maybe you know where is the problem?
Don't need the line $data->{$currentfile}=[]; -- the arrayref will be autovivfied (created automatically when needed) in push @{$data->{$currentfile}};

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.