http://www.perlmonks.org?node_id=1007856


in reply to Re: variable as hash name
in thread variable as hash name

Thank you, Dave. Now, the point is that I'm reading an external file in the following format:

230;238;101;103;138;146;112;116;; 230;238;101;103;146;146;108;112;; 224;238;0;0;146;146;110;118;; 238;238;0;0;146;146;112;114;;

I have an array named @loci_codes with this content:

@loci_codes = qw( Bet01 Bet05 Bet06 Bet12 );

What I want is to read each line ( <> ), split and put the elements in an array

while ( defined( $line = <> ) ) my @alelos = split ";", $line;

Than I want to take the elements of @alelos two by two and put each pair in a different hash. The PROBLEM is that I want each of these hashes to be named after on of the elements of @loci_codes.

while ( @loci_codes ) { $variable = shift @loci_codes; %$variable; $allele1 = shift @alelos; $allele2 = shift @alelos; %$variable{$allele1) += 1; %$variable{$allele2} += 1; }

And doing that for each line of the input, I want to have a hash named after a element of @loci_codes and populated with these pairs.

EXAMPLE:

%Bet01 = ( 230 => 2, 238 => 5, 224 => 1,); %Bet05 = ( 101 => 2, 103 => 2, 0 => 4, ); ...

NOTE: The content of @loci_codes may change according to the input file readed. THATS why I cant use static names for the hashes.

Replies are listed 'Best First'.
Re^3: variable as hash name
by GrandFather (Saint) on Dec 08, 2012 at 06:09 UTC

    so how is that superior to using an explicit "name" level in your hash? Using a variable as a name simply introduces exactly the same effect as adding a "name" level to a hash, but you have no easy way to debug your code. If you use a conventional hash you can use modules like Data::Dump (or better still, use an IDE or the debugger) to inspect the contents of the hash for debugging purposes. Consider:

    #!/usr/bin/perl use strict; use warnings; use Data::Dump; my @loci_codes = qw( Bet01 Bet05 Bet06 Bet12 ); my %data; for my $dataIn ( qw( 230;238;101;103;138;146;112;116;; 230;238;101;103;146;146;108;112;; 224;238;0;0;146;146;110;118;; 238;238;0;0;146;146;112;114;; ) ) { my @alelos = split ";", $dataIn; for my $code (@loci_codes) { ++$data{$code}{shift @alelos}; ++$data{$code}{shift @alelos}; } } Data::Dump::dump(\%data); for my $code (@loci_codes) { print "$code: "; print join ', ', map {"$_ ($data{$code}{$_})"} sort {$a <=> $b} keys %{$data{$c +ode}}; print "\n"; }

    prints:

    { Bet01 => { 224 => 1, 230 => 2, 238 => 5 }, Bet05 => { "0" => 4, "101" => 2, "103" => 2 }, Bet06 => { 138 => 1, 146 => 7 }, Bet12 => { 108 => 1, 110 => 1, 112 => 3, 114 => 1, 116 => 1, 118 => +1 }, } Bet01: 224 (1), 230 (2), 238 (5) Bet05: 0 (4), 101 (2), 103 (2) Bet06: 138 (1), 146 (7) Bet12: 108 (1), 110 (1), 112 (3), 114 (1), 116 (1), 118 (1)
    True laziness is hard work
Re^3: variable as hash name
by davido (Cardinal) on Dec 08, 2012 at 07:33 UTC

    I was hoping that you might come up with some interesting and compelling reason -- some problem that can only be solved by getting your hands dirty in the muck of the symbol table. Instead, I'm seeing a description of a problem that can be solved with one more layer of hard references; a hash of hashes, for example. That, you can read about in perldsc. GrandFather is right; you just need a higher level layer of abstraction; a hash of hashes.

    Your situation doesn't meet the criteria for a good reason to use symbolic references in any code that you intend to keep around on your hard drive for more than a few minutes. You've stated pretty clearly, however, that you're not open to other alternatives; you know what you want, and just needed us to show you how to do it. But as the old saying goes, "now you have two problems."

    It's easy to forget that the symbol table is little more than just a special hash. All of Perl's package globals live in hashes. Perl is implemented to hide that from you most of the time, but behind the scenes, they're there. You don't usually need to fiddle with Perl's hashes when you can create your own to fiddle with instead.


    Dave

Re^3: variable as hash name
by eyepopslikeamosquito (Archbishop) on Dec 08, 2012 at 06:06 UTC

    %Bet01 = ( 230 => 2, 238 => 5, 224 => 1,); %Bet05 = ( 101 => 2, 103 => 2, 0 => 4, );
    Why not simply have "Bet01", "Bet05", ... as keys in a hash? For example:
    my %bets = ( 'Bet01' => { 230 => 2, 238 => 5, 224 => 1 }, 'Bet05' => { 101 => 2, 103 => 2, 0 => 4 }, );

      Because these 'groups' names ( that I want to use as hash names ) will also come from a external file.

        That is not a reason to want to do it the way it is in your mind right now.

        It is rather funny to see this topic, as it is almost exactly the problem that dragged me into perl development in the first place. I almost did the same, and once everything "worked", problems started to arise.

        The solution, as others already stated in a more or less explicit way, is to make ONE (and only ONE) global (or at least in a scope as limited as possible) variable that contains all your hashes that you do not yet know about.

        my %all_my_hashes; $all_my_hashes{$variable} = { valorC => "value03", valorD => "value04" +, }; print $all_my_hashes{$variable}, "\n"; # later you read ; records while (<>) { # consider Text::CSV_XS with sep_char => ";" my @alelos = split ";" => $_, -1; while (@loci_codes) { $variable = shift @loci_codes; $all_my_hashes{$variable}; my $allele1 = shift @alelos; my $allele2 = shift @alelos; $all_my_hashes{$variable}{$allele1) += 1; $all_my_hashes{$variable}{$allele2} += 1; } $all_my_hashes{Bet01} = { 230 => 2, 238 => 5, 224 => 1, }; $all_my_hashes{Bet05} = { 101 => 2, 103 => 2, 0 => 4, };

        Note that the main difference is that you'd need to initialize as anonymous hashes instead of lists, so

        %$foo = ( 1, 2, ... ); => my %all_my_hashes; $all_my_hashes{$foo} = { 1 => 2, ... };

        Of course you can also use a ref as top-level, so the reference stands out better (for any value of better):

        my $all_my_hashes; $all_my_hashes->{$foo} = { 1 => 2, ... };

        One *huge* advantage with using a scalar reference is that you can easily (and safe and fast) pass that reference around to other parts of your program and limit the scope.

        Aut-vivivication is your friend!


        Enjoy, Have FUN! H.Merijn

        Because these 'groups' names ( that I want to use as hash names ) will also come from a external file.

        Exactly, they can all go into a hash, you can have

        $hashref->{group1}{dogs}{fido}{breed}='doberman'; $hashref->{group1}{dogs}{fido}{age}=12; $hashref->{group11}{humans}{larry}{age}= undef; ...
        or anything -- should really read varvarname