Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

Declaring and checking content of variables with consecutive names

by rflesch (Novice)
on Sep 23, 2016 at 11:34 UTC ( #1172453=perlquestion: print w/replies, xml ) Need Help??

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

Dear community,

in a Perl CGI script, how can I
(a) declare a set of 100 string variables $str0 .. $str99 in one loop in order to obtain

my $str0=''; (..) my $str99='';

(b) further down in the script, find out (in a loop) which of those are empty?

  • Comment on Declaring and checking content of variables with consecutive names
  • Download Code

Replies are listed 'Best First'.
Re: Declaring and checking content of variables with consecutive names
by Corion (Pope) on Sep 23, 2016 at 11:36 UTC

    Don't.

    The usual approach is to either use an array, @str, or a hash, %str.

    Access them as:

    my @str; $str[0] = ''; $str[1] = ''; ... $str[99] = ''; print join ",", @str;

    or for the hash version:

    my %str; $str{0} = ''; $str{1} = ''; ... $str{99} = ''; print join ",", map {$str{$_}} 0..99;

    See also Why it's stupid to `use a variable as a variable name'

      Thank you very much! Very much appreciated!
Re: Declaring and checking content of variables with consecutive names
by AnomalousMonk (Bishop) on Sep 23, 2016 at 17:23 UTC
    ... find out (in a loop) which of those are empty?

    One way for an array:

    c:\@Work\Perl\monks>perl -wMstrict -le "use Data::Dump qw(dd); ;; use constant INITIALIZER => ''; ;; my @strings = (INITIALIZER) x 6; dd \@strings; ;; @strings[1, 4] = qw(foo bar); dd \@strings; ;; my @empties = grep { $strings[$_] eq INITIALIZER } 0 .. $#strings; print qq{indices of empty elements: @empties}; " ["", "", "", "", "", ""] ["", "foo", "", "", "bar", ""] indices of empty elements: 0 2 3 5
    And a way for hashes:
    c:\@Work\Perl\monks>perl -wMstrict -le "use Data::Dump qw(dd); ;; use constant INITIALIZER => ''; ;; my %strings = map { $_ => INITIALIZER } 0 .. 5; dd \%strings; ;; @strings{1, 4} = qw(foo bar); dd \%strings; ;; my @empties = grep { $strings{$_} eq INITIALIZER } keys %strings; print qq{keys of empty values: @empties}; " { "0" => "", "1" => "", "2" => "", "3" => "", "4" => "", "5" => "" } { "0" => "", "1" => "foo", "2" => "", "3" => "", "4" => "bar", "5" => +"" } keys of empty values: 3 0 2 5
    (Keys of empty values are returned in random-ish order because hashes have no inherent ordering other than the key-value pairing of each hash element.)

    Update: From Perl version 5.12 onward, keys called in list context also acts with arrays to return a list of all the indices (the "keys", get it?) of the array, so in the array example, the statement
        my @empties = grep { $strings[$_] eq INITIALIZER } keys @strings;
    would have worked as well.


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

Re: Declaring and checking content of variables with consecutive names
by hippo (Canon) on Sep 26, 2016 at 16:08 UTC

    Since it is hopefully clear by now from the excellent answers which you have already received that going down this route would be A Bad Thing, I thought it might be worth writing a perlcritic policy to check for this. However, having done a little research today I am delighted to discover that such a policy already exists: Perl::Critic::Policy::Bangs::ProhibitNumberedNames.

    This sounds like a really good addition in and of itself. The Perl::Critic::Bangs bundle also has some other tempting-looking policies as well. Just thought this was worth mentioning as it was new to me and I would have used it long ago if I had known about it.

      If you read data fields from an instrument into arrays periodically (for example, data obtained with a digital oscilloscope every second) wouldn't it make sense to give the arrays consecutive names such as @arr0000, @arr0001, (..), @arr0234, (...)? Similarly, if you save these data to disc, the name of the array would become the corresponding file name. We do this all the time (but we don't use Perl in this context).

        That approach would suffer from exactly the same problems as consecutively enumerated scalar variables. Perl has arrays of arrays so this is easily avoided by having just one single outer array each of whose elements are themselves an array. That way your code could declare just one @arr and then index into it for individual subarrays or within them for individual values.

Re: Declaring and checking content of variables with consecutive names
by sir_jeff (Initiate) on Sep 26, 2016 at 11:08 UTC

    The extreme dodgy hack way (if you cannot use arrays) would be like this :

    for(0..99){ ${"str$_"}=""; }
    Yes very hacky I know but it does answer the question.
    Please do not use this code example in a live or production environment.
    -SJ-

      This is more of a reply to the OP:

      It's important to note that this code will not work when strict is enabled, and strict should always be turned on - in fact, modern versions of Perl turn it on for you if you say use v5.12; or higher at the top of the script. (See also Use strict and warnings)

      Disabling strict is something that should only be done if you know what you are doing and why. In this case, others have already explained why there are much better ways to do what you want.

      Regards,
      -- Hauke D

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1172453]
Approved by GotToBTru
Front-paged by kcott
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (2)
As of 2019-08-21 16:28 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?