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

Hello monks!
I have a file with many lines, and I want to pass the contents of each line to a different array, so for example @array1 will hold the data from line 1. @array2 will hold the data from line 2, etc...
The thing is, while I open the file and read it line by line, how can I create the different array dynamically? If I knew that I had X lines, I could create X arrays beforehand. But is there a way to use a counter and increment it each time you read a line and then use the number 1,2,3...of the counter to create the arrays?
$counter=0; open IN, $myfile; while(<IN>) { $line=$_; chomp $line; $counter++; $name_of_array="array_$counter"; } close IN;
apparently the line that I try to include the value of the counter in the array's name is not what I need. Can you help me?
  • Comment on Create dynamically different array names based on counter incrementation
  • Download Code

Replies are listed 'Best First'.
Re: Create dynamically different array names based on counter incrementation
by roboticus (Chancellor) on Jan 21, 2011 at 13:53 UTC

    You rarely have to create a variable name at runtime: Instead, try using an array of arrays. The first dimension would be your counter, and the second dimension would be your arrays. The syntax would look something like this:

    my @Arrays; my $counter=0; open my $IN, '<', $myfile or die; while (my $line = <$IN>) { chomp $line; ++$counter; # Put fields in Array[counter] $Arrays[$counter] = [ split /\t/, $line ]; # Use a single field print "Third column: $Arrays[$counter][2]\n"; }

    Read perlref, perldsc and perllol for more details on references, data structures and arrays of arrays.

    Untested, you keep all the pieces and other standard disclaimers apply...

    Having said all that, if you really want to create variables at runtime, be sure to check out Re: variable with $$ for a thread containing the method on how to do it, as well as references to articles describing why you don't really want to do it.

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

    Update: Made the fix suggested below by the Anonymous Monk.

      # Put fields in Array[counter] $Arrays[$counter] = split /\t/, $line;

      I think you meant:

      $Arrays[$counter] = [ split /\t/, $line ];

      or even (with autovivification) — though I consider that less readable:

      @{ $Arrays[$counter] } = split /\t/, $line;

      In scalar context (what you have), split returns the number of fields found (and older versions of Perl did split into the @_ array, issuing a "Use of implicit split to @_ is deprecated" warning).

Re: Create dynamically different array names based on counter incrementation
by JavaFan (Canon) on Jan 21, 2011 at 13:51 UTC
    You want an array of arrays. Something like:
    my @array; while (<IN>) { push @array, [extract_data_from_line $_]; }
    for some subroutine extract_data_from_line that turns a string into a list of data.
      shorter (and better to read for me)
      my @array = map [extract_data_from_line $_], <IN>;

        This needs twice as much memory, though (temporarily, for building the intermediate list).

        Usually, this won't be an issue, but it might be relevant when dealing with huge arrays, in order to limit peak memory usage.

Re: Create dynamically different array names based on counter incrementation
by Khen1950fx (Canon) on Jan 22, 2011 at 00:17 UTC
    If you just want line 1 to become array1, etc., then this works:
    #!/usr/bin/perl use strict; use warnings; my $file = '/path/to/file'; open FH, $file; my ( @arr, @AoA, $aref ); while (<FH>) { push @AoA, [split]; for $aref (@AoA) { print "[ @$aref ],\n"; } } close FH;