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

UPDATE: The answer was found with eval (see my response to mreece).

I'm trying to make an array of arrays, the member arrays of which have variable names. This variable-ness of the array names is necessary (unless someone has a better idea - I'm definitely open to it) because the array(s) to be used are specified at runtime by the user using Getopt::Std. The array names can't be predefined because they are being pulled from a datafile of arrays, which I don't own, that is auto-generated and could at any time have arrays added/deleted/renamed. Obviously, I don't want to rewrite with each new array, so variable names it is. Here's the issue. When I take the list of arrays specified on the command line, and add them to a new array, the new array stores their names as strings instead of simply importing the arrays' entries. Example: Here is what it would look like if I explicitly named them without variables: (much of the assumed stuff has been extracted)

use Getopt::Std; require "/path/filename"; # Here's my datafile. getopts('f:'); #Here's the part I'd like to have create my array of arrays #if ( $opt_f ) { # chomp $opt_f ; # @combined = $opt_f; # The offending line. #} #Here's what would work, if only the names weren't variable @combined = ( @array1,@array2); foreach $entry ( @combined ) { print "return: $entry \n"; }
If Getopt is bringing in $opt_f which is a string "@array1,@array2,@et_cetera", how can I get it to work properly in my "@combined..." statement? I've RTFM, and I'm sure the answer's there, but I've spent way too much time on this particular issue.

Replies are listed 'Best First'.
Re: Array of Arrays with Variable Names
by jeffa (Bishop) on Aug 25, 2006 at 17:09 UTC

    I'm not really following what you are trying to do, but it sounds to me like you need either a Hash of Arrays or an Array of Hashes (where the hashes are a single key => value pair and the value is your array) if you need to preserve order.

    #!/usr/bin/perl -l use strict; use warnings; my %unordered = ( foo => [qw(foo baz baz)], bar => [0 .. 9], ); print for @{ $unordered{foo} }; print "--------"; my @ordered = ( { foo => [qw(foo baz baz)] }, { bar => [0 .. 9] }, ); print for @{ $ordered[1]->{bar} };
    Hope this helps. :/

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
      This reply apples to at least two of the above entries, the third I haven't had a chance to address. All of the data is being pulled in from a file of the following structure:
      @array1=( 'entry1', 'entry2', ... ); @array2=( 'entry1', 'entry2, ... ) ...
      There are a few rules I have to follow here: 1. I can not modify the format of the data file - it is not static, nor do I 'own' it where I can change the way it's generated. 2. The arrays can not be in the script itself . I guess the whole question boils down to this, how can I have the following:
      @combined = ( $opt_f );
      ..interpret the following:
      $opt_f = '@array1,@array2'
      As a list of arrays which are then combined, and not simply treat them as regular entries, strings "@array1", "@array2"?
        if you absolutely must do it this way, here is how (use eval):
        ## this is an example, works just as well if these arrays come from a +require'd file my @array1 = qw(a b c); my @array2 = qw(d e f); ## again, just an example, works just as well if this comes from GetOp +t my $opt_f = '@array1, @array2'; ## here is the magical and evil eval my @combined = eval "$opt_f"; print "@combined\n";
Re: Array of Arrays with Variable Names
by madbombX (Hermit) on Aug 25, 2006 at 17:07 UTC
    First off, it is very difficult to determine if there is a better way of structuring the data when you haven't presented us with any example data. This node on Re: How can I visualize my complex data structure? was suggested to me a while back and has been fantastically useful with trying to actually visualize my complex data structures. Especially when I am forced to work with data that I don't have control over how its handed to me.

    That being said, have you considered an array of hashes. Since a hash is, at its simplest, an associative array, you can create an array with named hashes. But like I said before, without example data, its difficult to help you any further with organizing data.

    Depending on how the datafile is structured (also something that would be helpful if you provide), you do something like the following:

    @combined = split /,/, $opt_f;

    Side note, I am a personal fan of using GetOpt::Std with the hash format this way I can always Data::Dumper all the options provided as opposed to just one at a time:

    use Getopt::Std qw(getopts); getopts('f:', \%opt); if ($opt{'f'}) { ... } # Debug print Dumper (\%opt);

    Eric

Re: Array of Arrays with Variable Names
by mreece (Friar) on Aug 25, 2006 at 17:08 UTC
    consider using a hash to store your arrays.
    my %arrays = ( array1 => [qw( a b c )], array2 => [qw( d e f )], ); my @combined = ( @{ $arrays{array1} }, @{ $arrays{array2} } );
    this makes it easy to replace 'array1' with a variable, $array_name.

    see How can I use a variable as a variable name?

Re: Array of Arrays with Variable Names
by roboticus (Chancellor) on Aug 25, 2006 at 17:29 UTC
    JWM:

    You rarely want to have a variable name itself be variable, for many good reasons. If you don't know how to do it, you probably don't really want it. (I'll insert a link to a node that describes the technique and caveats as soon as I [id://Super Search|find it] again. Also, I'm not being snotty, I don't know how to do it either.)

    However, the technique described by madbombX and mreece is usually the best way to do the job. Here's a quickie example on how to use the technique:

    #!/usr/bin/perl -w use strict; use warnings; my %hr = ( 'default' => [ 1 .. 9], 'even' => [ 0, 2, 4, 6, 8], 'odd' => [ 1, 3, 5, 7, 9], ); my $arrname = shift || 'default'; print "Array $arrname contains:\n"; my $ar = $hr{$arrname}; for my $cnt (0 .. $#{$ar}) { printf "\t %s[%d]=%s\n", $arrname, $cnt, $ar->[$cnt]; }

    Running this yields:

    roboticus@swill ~/PerlMonks $ ./var_array_names.pl even Array even contains: even[0]=0 even[1]=2 even[2]=4 even[3]=6 even[4]=8 roboticus@swill ~/PerlMonks $ ./var_array_names.pl odd Array odd contains: odd[0]=1 odd[1]=3 odd[2]=5 odd[3]=7 odd[4]=9

    --roboticus

    UPDATE: Yarch! I was a bit slow, and several people beat me to the punch. Oh, well. Anyway, here are links to a few of the threads describing the pro & cons:

  • variable with $$ see response Re: variable with $$!
  • Dynamically Building Variable Names
  • construct variable name on the fly by aquarium
  • Variable name containing a variable
  • and the list goes on and on...
Re: Array of Arrays with Variable Names
by wojtyk (Friar) on Aug 25, 2006 at 17:18 UTC
    It's ugly and unrecommended, but you can do it with eval. For instance...the following code prints out the first argument of the $string array, evaluated at run-time:

    print eval('@'.$string.'[0]');

    In your case, I think what you're looking for is something like:

    foreach $entry ( @combined ) { my $array = eval('\@'.$entry); }

    You can do similar incredibly ugly and horribly unrecommended things with eval, but if it gets the job done, it does ;)

    I think you can use map to do something similar (see Perl Best Practices pg. 161 "Avoid string eval") which states this kind of behavior is best avoided.

Re: Array of Arrays with Variable Names
by GrandFather (Saint) on Aug 25, 2006 at 20:35 UTC

    Why are you not using a hash?

    From the Getopt::Stddocumentation: "getopt() and getopts() will also accept a hash reference as an optional second argument. Hash keys will be x (where x is the switch name)".


    DWIM is Perl's answer to Gödel
Re: Array of Arrays with Variable Names
by wojtyk (Friar) on Aug 25, 2006 at 17:22 UTC
    Btw, my suggestion was assuming these arrays were already populated and living in some other file which you can't touch. If you get to generate your own from scratch, hash key pointing to array is definitely the way to go.