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

I have a variable $tgs in a subroutine. I need this variable to be a part of the name of a hash like below
sub xyz { my $tgs = @_; my %Test_hash_${tgs}; ... .. }
but this gives error. Can any monk please tell me how to achieve this?

Replies are listed 'Best First'.
Re: Perl Variables
by johngg (Canon) on May 14, 2007 at 14:53 UTC
    Firstly, your subroutine is not going to do what you think. This line

    my $tgs = @_;

    is going to assign the number of elements in @_ to $tgs because the LHS is in scalar context. Do this

    my ($tgs) = @_;

    or this

    my $tgs = shift;

    instead.

    Rather than trying to make the contents of $tgs part of the hash name, you might be able to accomplish what you need using a HoH structure. Something like

    my %Test_hash; ... sub xyz { my ($tgs) = @_; $Test_hash{$tgs} = {a => 1, b => 2}; ... } ...

    I hope this is of interest.

    Cheers,

    JohnGG

Re: Perl Variables
by jettero (Monsignor) on May 14, 2007 at 14:39 UTC

    First of all, if I were you I'd check out perldata and perlref.

    Second, you can probably do this relatively cleanly with eval:

    my $tgs = shift; # scalar. my %hash = ( $tgs => 1 ); # sane-ish $hash{$tgs} = 1; # also sane-ish eval "my %Test_hash_$tgs = ()"; # why do this? die $@ if $@; # explode if it didn't work

    Let me ask this: What are you trying to achieve?

    -Paul

      I have a script where I open a directory in which I have n number of directories and I need to load all files in these directories into a hash. So I am trying to name the hash with the name of the directory which is in a variable. something like this
      if ( !opendir( DIR, "$myDirectory")) { &Util::Status($StatusFile, "Couldn't open $myDirectory"); exit 1; } @Dirs = readdir( DIR ); closedir( DIR ); foreach $tgs (@Dirs) { $TGSet = "${myDirectory}/$tgs"; $DataDir = "${TGSet}/DW_DataToLoad"; next if $tgs =~ /^\.\.?$/; if ( -f "${DataDir}/ready_for_loading") { &Lock_File($StatusFile, $TGSet); unlink ( "${DataDir}/ready_for_loading"); $DW_file_GL = "${myDirectory}/DW_input_GL"; $DW_file_nonGL = "${myDirectory}/DW_input_nonGL"; &PrepareDWFile( $StatusFile, $DW_file_GL, GL); &prepareDWFile( $StatusFile, $DW_file_nonGL, nonGL); if ( ! opendir( DATA, "$DataDir")) { &Util::Status($StatusFile, "Couldn't open $DataDir"); exit 1; } @tgdir = readdir( DATA); foreach $task (@tgdir) { next if $task =~ /^\.\.?$/; ($task_name) = $task =~ m#(.*)\.txt$#i; if ( ! open (FILE, "$task")) { &Util::Status($StatusFile, "Error: Couldn't open $task_ +name file for reading"); exit 1; } @{$task_name} = <FILE>; } $TGS_Value_$tgs{VAR} = \@VAR; $TGS_Value_$tgs{STR} = \@STR; $TGS_Value_$tgs{PER} = \@PER; $TGS_Value_$tgs{MKT} = \@MKT; $TGS_Value_$tgs{INS} = \@INS; $TGS_Value_$tgs{GL} = \@GL; yet to complete it
      Please help

        In this case, I think a hash of hashes is definitely the way to go.

        $TGS_Value{$tgs}{VAR} = \@VAR; $TGS_Value{$tgs}{STR} = \@STR; $TGS_Value{$tgs}{PER} = \@PER; $TGS_Value{$tgs}{MKT} = \@MKT; $TGS_Value{$tgs}{INS} = \@INS; $TGS_Value{$tgs}{GL} = \@GL;
Re: Perl Variables
by liverpole (Monsignor) on May 14, 2007 at 14:40 UTC
    Hi Nalina,

    You can't do it that way.  But then, why would you want to have a hash whose name can differ, depending on your variable $tgs?

    Just stick with a known hash name, like my %Test_hash.  It's lexically scoped to within the subroutine, so it can't interfere with anything outside of the subroutine.

    If you really think you need to have a "dynamically named variable", please explain why you think so, and we can suggest an alternative that does what you need.


    s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/
Re: Perl Variables
by kyle (Abbot) on May 14, 2007 at 14:47 UTC

    That's probably not a good idea. That said, eval might be the answer.

    sub xyz { my ($tgs) = @_; return eval <<"END_OF_SUB_XYZ"; my %Test_hash_$tgs; my \$other = "Why did I do this?"; print "\$other Now I have to escape so many things.\n"; END_OF_SUB_XYZ ; }

    But again, let me emphasize, I do not recommend that.

    Then again, maybe a symbolic reference would work, but that's disallowed by use strict.

    sub xyz { my ($tgs) = @_; my $hash_name = "Test_Hash_$tgs"; my %{$hash_name}; }

    My guess is that it would be best to have a hash of hashes.

    sub xyz { my ($tgs) = @_; my %Test_hash{$tgs} = {}; # use $Test_hash{$tgs}{foo}, etc. }

    It might help to have a look at perlref.

Re: Perl Variables
by naikonta (Curate) on May 14, 2007 at 14:45 UTC
    Wow, you're slightly ahead to use Perl 6, well sort of :-)

    Saying,

    my %A_Hash; #or my %B_Hash = (); #or my %C_Hash = (one => 1);
    means declaring a hash (%A_Hash), or declaring and initailizing it with empty element (%B_Hash), or declaring and initializing it with some element (%C_Hash). While,
    my $value = $Some_Hash{a_key}; #or my $other_value = $Some_Hash{$key};
    means obtaining a value of a_key or $key element from %Some_Hash.

    Can you see the difference? The perldata says more about this. Another thing, $tgs = @_; means that $tgs will contain the number of elements of @_. If you want to get the (first) element, you would say ($tgs) = @_;, or $tgs = shift.

    And yes, saying %Some_Hash{key} to get the value of 'key' element of %Some_Hash is introduced in Perl 6.


    Open source softwares? Share and enjoy. Make profit from them if you can. Yet, share and enjoy!

Re: Perl Variables
by Anonymous Monk on May 19, 2007 at 12:30 UTC