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

Hey Monks,

I'm having an issue with a script I wrote trying to populate an array of hashes.

I don't quite know why it's not working, most likely I just need an extra set of eyes to help me out.

What I'm trying to accomplish is the following result:
$VAR1 = { 'BNA' => 'Medium Batch 1 Department', 'SNO' => '1', 'products' => [ { 'PNO' => '5001', 'CCO' => 'SPIA', 'DNO' => '1' }, { 'PNO' => '5004', 'CCO' => 'SPIA', 'INO' => '5004', 'DNO' => '1' }, { 'PNO' => '5100', 'CCO' => 'SPIA', 'INO' => '5100', 'DNO' => '1' } ], 'BNO' => '669' }; $VAR2 = { 'BNA' => 'Medium Batch 2 Department', 'SNO' => '1', 'products' => [ { 'PNO' => '5001', 'CCO' => 'SPIA', 'DNO' => '1' }, { 'PNO' => '5004', 'CCO' => 'SPIA', 'INO' => '5004', 'DNO' => '1' }, { 'PNO' => '5100', 'CCO' => 'SPIA', 'INO' => '5100', 'DNO' => '1' } ], 'BNO' => '670' };
I'm trying to achieve this with the following code, but it just doesn't seem to be working out for me, any ideas?
#!perl use strict; use Data::Dumper; use warnings; my $Delimiter = chr(253); my %HostHash; my (@HostArray, @ProductArray); my $FIRST = 0; HOSTPARSE: while (<DATA>) { s/^\s+|\s+$//g; my @fields = split(/$Delimiter/, $_); my %fields; foreach my $field (@fields) { my $a1 = substr($field, 0, 3); my $a2 = substr($field, 3); $fields{$a1} = $a2 if $a2; } if ($fields{BNA}) { print "$fields{BNA} \n"; if ($FIRST) { print "Storing Products in Batch $HostHash{BNA}\n"; $HostHash{products} = \@ProductArray; @ProductArray = (); push @HostArray, \%HostHash; } else { $FIRST = 1; } %HostHash = %fields; next HOSTPARSE; } push @ProductArray, \%fields; } print "Storing Products in Batch $HostHash{BNA}\n"; $HostHash{products} = \@ProductArray; push @HostArray, \%HostHash; print Dumper @HostArray; __DATA__ BNAMedium Batch 1 DepartmentýBNO669ýSNO1ý CCOSPIAýDNO1ýPNO5001ýSAD0ýINO0ý CCOSPIAýDNO1ýPNO5004ýSAD0ýINO5004ý CCOSPIAýDNO1ýPNO5100ýSAD0ýINO5100ý BNAMedium Batch 2 DepartmentýBNO670ýSNO1ý CCOSPIAýDNO1ýPNO5001ýSAD0ýINO0ý CCOSPIAýDNO1ýPNO5004ýSAD0ýINO5004ý CCOSPIAýDNO1ýPNO5100ýSAD0ýINO5100ý
Thanks in advance!

Replies are listed 'Best First'.
Re: Arrary of Hashes populating issue
by davido (Cardinal) on Jan 27, 2005 at 16:38 UTC

    Since some of the variables that you're taking references to within the loops were declared outside the loops, they never fall out of scope from iteration to iteration. Hense, for those variables, you're dealing with the same memory location, same variable each time you take a reference to it while constructing your datastructure.

    You should either redesign your lexical scoping so that you get a new variable on each iteration, or (easier) you should change all \@varname to  [ @varname ], and all \%varname to  { %varname }.

    The anonymous array constructor, and the anonymous hash constructor will create entirely new anon arrays / anon hashes, instead of reusing the same ones. You might have a look at perlreftut and perlref for info on these constructors.


    Dave

      Thanks Dave!

      You ARE right on the mark. Everything works great.

      Thanks again!
Re: Arrary of Hashes populating issue
by dragonchild (Archbishop) on Jan 27, 2005 at 16:45 UTC
    First off, s/^\s+|\s+$//g; isn't doing what you think it's doing, but that's not your problem.

    Your problem is that you're making it too difficult for yourself. Either

    • the line begins with BNA, in which case you have a new entry
    • the line doesn't being with BNA, in which case you push it onto the fields array of the last entry you saw.
    my @stuff; while (<DATA>) { my @fields = split $Delimiter, $_; my ($type, $name) = $fields[0] =~ /^(...)(.*)/; if ($type eq 'BNA') { # I don't know what other data you want to keep from the BNA l +ine ... push @stuff, { name => $name, products => [], }; next; } # I don't know what you want to do with this, so I'll just keep it + there. push @{$stuff[-1]{products}}, $_; }

    Code is untested, but should work just fine.

    Being right, does not endow the right to be rude; politeness costs nothing.
    Being unknowing, is not the same as being stupid.
    Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
    Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

Re: Arrary of Hashes populating issue
by sweetblood (Prior) on Jan 27, 2005 at 16:42 UTC
    Davido is right on the mark, the only thing I would add is to check out perldoc perldsc

    Good luck

    Sweetblood