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

Hello all,

I've looked all over SoPW for some information on how to implement array soft references, but no luck. I'm having trouble making my script more flexible with array naming.

As you can see, I'm defining the array names at the top (I know what they will be called when they are parsed in), but when it comes to populating them, I'd like the flexibility. I'm using "no strict 'refs';" and eval. I'd rather use "use strict" if possible and write clean code, but then it turns into a very rigid set of 'if' statements that requires much more editing.

Perhaps someone can point me to a better solution...

Thanks, smknjoe

#!/usr/bin/perl #use strict; no strict 'refs'; use warnings; my @table_min_1; my @table_min_2; my @table_max_1; my @table_max_2; my @fields; my $array_name; my $item; while (my $lines = <DATA>) { chomp($lines); if ($lines =~ /Array\s+(\w+)\s+(\d+)/) { # array ref $array_name = "\$table_" . $1 . "_" . $2; } else { @fields = split(/\s+/,$lines); my $value = $fields[1]; #print "debug: $array_name \n"; eval "push @{$array_name}, $value"; } } foreach $item (@table_min_1) { print "$item\n"; } foreach $item (@table_min_2) { print "$item\n"; } foreach $item (@table_max_1) { print "$item\n"; } foreach $item (@table_max_2) { print "$item\n"; } __DATA__ Array max 1 useless_text_field a useless_text_field b useless_text_field c Array max 2 useless_text_field 1 useless_text_field 2 useless_text_field 3 Array min 1 useless_text_field d useless_text_field e useless_text_field f Array min 2 useless_text_field 4 useless_text_field 5 useless_text_field 6
The code should simply dump out:
a b c 1 2 3 d e f 4 5 6

Replies are listed 'Best First'.
Re: Soft Array Refs
by stevieb (Canon) on Jun 23, 2015 at 22:45 UTC

    Don't do it. Here's a valuable and entertaining three part story by Mark-Jason Dominus as to why doing these things should be avoided wherever possible. There are many other stories out there stating why this isn't such a good idea unless you *really* know what you're doing.

    Hashes are designed for this. Here's an example. Just ask if you have questions. Usually, it's the dereferencing that confuses most people.

    #!/usr/bin/perl use strict; use warnings; use Data::Dumper; my %data; my $array_name; while (my $line = <DATA>) { chomp($line); if ($line =~ /Array\s+(\w+)\s+(\d+)/) { $array_name = "table_" . $1 . "_" . $2; next; } my $value = (split /\s+/, $line)[1]; push @{ $data{$array_name} }, $value; } print "Printing entire structure:\n"; print Dumper \%data; print "\nPrinting all values from all arrays:\n\n"; for my $key (keys %data){ print "in array '$key'\n"; for my $elem (@{ $data{$key} }){ print "$elem\n"; } } print "\nPrinting values only from 'table_min_1':\n"; for my $item (@{ $data{'table_min_1'} }){ print "$item\n"; } __DATA__ Array max 1 useless_text_field a useless_text_field b useless_text_field c Array max 2 useless_text_field 1 useless_text_field 2 useless_text_field 3 Array min 1 useless_text_field d useless_text_field e useless_text_field f Array min 2 useless_text_field 4 useless_text_field 5 useless_text_field 6

    -stevieb

      Thanks Stevie.

      I regretted posting it about 30 minutes later after I had two words for myself: "associative arrays", aka a hash.

      Up to now, I've gotten by with arrays for everything but now I see a true need for using a hash.

        Rule of thumb: If order matters, use an array; otherwise use a hash.

        Most of the time, you should use a hash because of its expressive power. You can think of a hash as a miniature symbol table, if it helps. :)

Re: Soft Array Refs
by Athanasius (Cardinal) on Jun 24, 2015 at 05:38 UTC

    Hello smknjoe,

    As stevieb has shown, a hash is a much better option here. But, for the record, you need no strict 'refs' only if you’re not using eval — in which case, you also have to use package global variables (see perlref#Symbolic-references):

    use strict; use warnings; our (@table_min_1, @table_min_2, @table_max_1, @table_max_2, $array_na +me); while (<DATA>) { chomp; if (/Array\s+(\w+)\s+(\d+)/) { $array_name = 'table_' . $1 . '_' . $2; } else { no strict 'refs'; my @fields = split /\s+/; push @$array_name, $fields[1]; } } print "\n"; print "$_ " for @table_max_1, @table_max_2, @table_min_1, @table_min_2 +; print "\n"; __DATA__ ...

    On the other hand, if you are using eval, you can use strict without qualification, along with my lexicals:

    use strict; use warnings; my (@table_min_1, @table_min_2, @table_max_1, @table_max_2, $array_nam +e); while (<DATA>) { chomp; if (/Array\s+(\w+)\s+(\d+)/) { $array_name = '@table_' . $1 . '_' . $2; # ^ } else { my @fields = split /\s+/; eval qq(push $array_name, "$fields[1]"); } } print "\n"; print "$_ " for @table_max_1, @table_max_2, @table_min_1, @table_min_2 +; print "\n"; __DATA__ ...

    Note the additional @ in the second example. In both cases, the output is as desired:

    15:43 >perl 1283_SoPW.pl a b c 1 2 3 d e f 4 5 6 15:43 >

    But, again, don’t do that! :-)

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      Ah so,

      I was somewhat close. I'm still fairly clueless on some of the syntactical subtleties in Perl - single quotes around '@table' for example. I love your printing shortcut at the end - I learn something new everyday. I'm looking to write this code CORRECTLY using hashes instead.

      Thx, Joe
        ... single quotes around '@table' ...

        If double-quotes has been used, double-quotish interpolation of an array named  @table_ would have been attempted and, with strict fully enabled (as it is in Athanasius's code), would have crashed compilation. Single-quotes do not interpolate. (Update: The  @ sigil could also be escaped in double-quotes.)

        c:\@Work\Perl\monks>perl -le "use warnings; use strict; ;; print qq{@table}; " Possible unintended interpolation of @table in string at -e line 1. Global symbol "@table" requires explicit package name at -e line 1. Execution of -e aborted due to compilation errors. c:\@Work\Perl\monks>perl -le "use warnings; use strict; ;; my @table = qw(fee fie foe); ;; print qq{double-quote array interpolation: (@table)}; ;; print q{single-quote, no interpolation: (@table)}; ;; print qq{double-quote, sigil escaped: (\@table)}; " double-quote array interpolation: (fee fie foe) single-quote, no interpolation: (@table) double-quote, sigil escaped: (@table)

        Update: Changed code examples to consolidate compiling code examples into single group of statements.


        Give a man a fish:  <%-(-(-(-<