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

Hi Wise Monks,

I've got this application at work which begs for the following data structure - a hash of hashes of arrays. And I just do not know the syntax for populating such a data structure, much less printing it out.

The following is sort of a test bed. First, a data file of made up data for which I want to populate four arrays.

packers 4 40 400 4000 patriots 6 62 436 3987 colts 8 74 892 7666 bears 9 88 912 9550 packers 3 44 410 4200 patriots 7 66 510 3800 colts 10 77 910 7000 bears 11 88 1010 9410 packers 2 36 385 4105 patriots 4 58 500 3700 colts 9 75 900 7500 bears 8 95 1017 10200 packers 4 37 388 4378 patriots 6 55 440 4987 colts 8 80 843 8210 bears 9 101 890 9998 packers 7 40 400 4000 patriots 11 62 436 3987 colts 7 74 892 7666 bears 12 88 912 9550 packers 2 48 422 4320 patriots 3 54 510 3765 colts 6 72 812 7500 bears 7 86 899 9430
And the following is a code attempt (well, one of quite a few, actually):

#!/usr/bin/perl -w #use strict open (TEST,">test.txt"); my ($team,$points,$tallies,$scores,$metrics); my %teamStats = (); open (STATS,"<testData.txt"); while (<STATS>) { @stuff = split(/\s+/,$_); $team = $stuff[0]; $points = $stuff[1]; $tallies = $stuff[2]; $scores = $stuff[3]; $metrics = $stuff[4]; unless ($teamStats{$team}) { $teamStats{$team} = {}; } &fillTeamHash($teamStats{$team},$points,$tallies,$scores,$metrics) +; } #while(($key, $value) = each(%HASH)) { foreach $team (keys %teamStats) { print "\n\nTeam:\t$team\n"; #@pointsArray = $teamStats{$team}{'pointsArray'}; #foreach $item (@pointsArray) #foreach $item ($teamStats{$team}{'pointsArray'}) #{ # print "$item\n"; #} } close (TEST); sub fillTeamHash { my ($teamHashPtr,$points,$tallies,$scores,$metrics) = @_; #$pointsArray = $$teamHashPtr{'pointsArray'}; #$talliesArray = $$teamHashPtr{'talliesArray'}; #$scoresArray = $$teamHashPtr{'scoresArray'}; #$metricsArray = $$teamHashPtr{'metricsArray'}; #print "In sub:\t$points\n"; #push (@$pointsArray,$points); push (@$$teamHashPtr{'pointsArray'},$points); #foreach $item (@$pointsArray) foreach $item (@$$teamHashPtr{'pointsArray'},$points) { #$size = @$pointsArray; $size = @$$teamHashPtr{'pointsArray'}; print TEST "Array Size:\t$size\t"; print TEST "Printing points array:\t$item\n"; } #push (@$talliesArray,$tallies); #push (@$scoresArray,$scores); #push (@$metricsArray,$metrics); }


If someone could tell me the syntax for such a problem, great. If someone could explain the WHY of the correct syntax, even better!

Thanks In Advance,

Tony (o2)

Replies are listed 'Best First'.
Re: Need Help With Syntax for (Complicated for Me) Data Structure
by Limbic~Region (Chancellor) on Jan 29, 2007 at 22:56 UTC
    o2bwise,
    It seems like what you want is actually a HoAoA.
    #!/usr/bin/perl use strict; use warnings; my %data; while (<DATA>) { chomp; my ($team, @field) = split; push @{ $data{$team} }, \@field; }

    This creates a single hash entry for each team. The value is a reference to an array of all entries for that team. Each entry is an array reference to the specific stats for that entry.

    Alternatively, you could do the HoHoA. Added implementation below.

    #!/usr/bin/perl use strict; use warnings; use constant TEAM => 0; use constant POINTS => 1; use constant TALLIES => 2; use constant SCORES => 3; use constant METRICS => 4; my %data; while (<DATA>) { chomp; my @col = split; push @{ $data{$col[TEAM]}{POINTS} }, $col[POINTS]; push @{ $data{$col[TEAM]}{TALLIES} }, $col[TALLIES]; push @{ $data{$col[TEAM]}{SCORES} }, $col[SCORES]; push @{ $data{$col[TEAM]}{METRICS} }, $col[METRICS]; }

    Cheers - L~R

      Thank you. I got pulled in quite a few directions, but I have saved youyr code and will study it. It sure looks nice and succinct!

      Tony
      Hi,

      I just want to say that perhaps the biggest thing I learned was the need to surround the array with braces. I never noticed that before! And I saw it in all three replies to my post.

      I am wondering if you know any reference that discusses this syntax.

      Thanks again,

      Tony
Re: Need Help With Syntax for (Complicated for Me) Data Structure
by GrandFather (Saint) on Jan 29, 2007 at 23:08 UTC

    A hash slice solves the problem (see perldata - slice):

    use strict; use warnings; my %teamStats; my @paramNames = ('points', 'tallies', 'scores', 'metrics'); while (<DATA>) { chomp; my ($team, @params) = split /\s+/; next if @params < 4; # Populate new hash using a hash slice my %newParams; @newParams{@paramNames} = @params; push @{$teamStats{$team}}, \%newParams; } foreach my $team (keys %teamStats) { print "\n\nTeam:\t$team\n"; print "\t", join ("\t", @paramNames), "\n"; for my $game (@{$teamStats{$team}}) { # Hash slice to the rescue again print "\t", join ("\t", @$game{@paramNames}), "\n"; } } __DATA__ packers 4 40 400 4000 patriots 6 62 436 3987 colts 8 74 892 7666 bears 9 88 912 9550 packers 3 44 410 4200 patriots 7 66 510 3800 colts 10 77 910 7000 bears 11 88 1010 9410

    Prints:

    Team: colts points tallies scores metrics 8 74 892 7666 10 77 910 7000 Team: patriots points tallies scores metrics 6 62 436 3987 7 66 510 3800 Team: packers points tallies scores metrics 4 40 400 4000 3 44 410 4200 Team: bears points tallies scores metrics 9 88 912 9550 11 88 1010 9410

    Update: cleaned up a little "legacy" code


    DWIM is Perl's answer to Gödel
      Thanks, Grandfather,

      I got pulled in a few directions, but will have a look tomorrow. I have it saved on my box.

      Tony
      Hi,

      I just want to say that perhaps the biggest thing I learned was the need to surround the array with braces. I never noticed that before! And I saw it in all three replies to my post.

      I am wondering if you know any reference that discusses this syntax.

      Thanks again,

      Tony

        "complicated" data structures are really simple data structures that refer to other data structures. That is, generally you are dealing with scalars, arrays (that can only store scalars) or hashes (that can only store scalars). The trick is that a scalar can store a reference to other things. HoHoA and all the other variants work by storing references so the good oil you are looking for is References quick reference from the Tutorials section.


        DWIM is Perl's answer to Gödel
Re: Need Help With Syntax for (Complicated for Me) Data Structure
by johngg (Canon) on Jan 29, 2007 at 23:17 UTC
    Being from the "wrong" side of the pond, I'm not sure exactly what you want. Limbic~Region has given you a HoAoA solution while I was working on a HoHoA solution. Here's the code

    use strict; use warnings; use Data::Dumper; my %teams = (); while ( <DATA> ) { chomp; my ($team, $points, $tallies, $scores, $metrics) = split; push @{ $teams{$team}->{points} }, $points; push @{ $teams{$team}->{tallies} }, $tallies; push @{ $teams{$team}->{scores} }, $scores; push @{ $teams{$team}->{metrics} }, $metrics; } my $dd = Data::Dumper->new([\%teams], [qw{*teams}]); print $dd->Dumpxs(); __END__ packers 4 40 400 4000 patriots 6 62 436 3987 colts 8 74 892 7666 bears 9 88 912 9550 packers 3 44 410 4200 patriots 7 66 510 3800 colts 10 77 910 7000 bears 11 88 1010 9410 packers 2 36 385 4105 patriots 4 58 500 3700 colts 9 75 900 7500 bears 8 95 1017 10200 packers 4 37 388 4378 patriots 6 55 440 4987 colts 8 80 843 8210 bears 9 101 890 9998 packers 7 40 400 4000 patriots 11 62 436 3987 colts 7 74 892 7666 bears 12 88 912 9550 packers 2 48 422 4320 patriots 3 54 510 3765 colts 6 72 812 7500 bears 7 86 899 9430

    and here's the output

    The top-level hash is keyed by team and there is for each team a sub-hash for each of points, tallies, scores and metrics, the values in each case being an array of said points etc. Thus, for points, we want $teams{$team}->{points} to be an array so enclosing it in the @{ ... } de-references the value in that sub-hash to get at the array so that the push can add another element to the end. Note also that the anonymous array will be created (autovivified) if it didn't exist already.

    I probably haven't explained this very well. Reply with more questions if it isn't clear.

    Cheers,

    JohnGG

      Man, that's great, JohnGG.

      I got pulled away in, but saved your code and will have a look tomorrow.

      I sure appreciate the output too.

      Tony