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

I'm trying to use (for the first time) a hash of anonymous hashes to hold a set of data records from a delimited flat ascii file. I will at some point need to add, edit, and delete records from this set but they must be put back into this flat file as other applications use this file.
Currently we use vi to manage these data and all kinds of problems are introduced using vi.

The code I'm working with(doesn't work) is as follows:

#!/usr/bin/perl -w use strict; our %rets; open(RL, "</home/myftplog") || open (RL, "<h:\\myftplog") || die "$!\n"; while (<RL>) { chomp; next if /^$/; my ($fn, $rl, $mle, $rce, $mlfn, $mlln, $mlac, $mlpn, $ml2e, $ml2fn, $ml2ln, $ml2pn, $retname, $ml2ac, $rc2e, $fc, $retid, $scrname, $exec, $freq, $fnum) = split /:/; if ($fnum eq ""){ my $fnum = "_001"; } %rets = ( ${retid}.${fnum} => { FNAME => $fn, RECLEN => $rl, LIAISON_EMAIL => $mle, LIAISON_FNAME => $mlfn, LIAISON_LNAME => $mlln, LIAISON_AREACODE => $mlac, LIAISON_PHONE => $mlpn, LIAISON2_EMAIL => $ml2e, LIAISON2_FNAME => $ml2fn, LIAISON2_LNAME => $ml2ln, LIAISON2_PHONE => $ml2pn, RETNAME => $retname, RETAILER_EMAIL => $rce, LIAISON2_AREACODE => $ml2ac, RETAILER2_EMAIL => $rc2e, FTPCHECK => $fc, RETID => $retid, SCRIPT_NAME => $scrname, EXECFLAG => $exec, FREQUENCY => $freq, FILE_NUMBER => $fnum } ); } close RL; foreach my $id (keys %rets) { print "$id\n"; }

when I execute this I get no errors. However I only have one record in %rets. I thought I would have had a separate reference to each %rets=>$retid.$fnum
I'm very confused. I do tink I'm close but I still need help!

Replies are listed 'Best First'.
Re: Hash of anonymous hashes --- Oh my
by !1 (Hermit) on Nov 17, 2003 at 18:41 UTC

    You're clobbering %rets. You should instead do:

    $rets{"$retid$fnum"} = { FNAME => $fn, RECLEN => $rl, LIAISON_EMAIL => $mle, LIAISON_FNAME => $mlfn, LIAISON_LNAME => $mlln, LIAISON_AREACODE => $mlac, LIAISON_PHONE => $mlpn, LIAISON2_EMAIL => $ml2e, LIAISON2_FNAME => $ml2fn, LIAISON2_LNAME => $ml2ln, LIAISON2_PHONE => $ml2pn, RETNAME => $retname, RETAILER_EMAIL => $rce, LIAISON2_AREACODE => $ml2ac, RETAILER2_EMAIL => $rc2e, FTPCHECK => $fc, RETID => $retid, SCRIPT_NAME => $scrname, EXECFLAG => $exec, FREQUENCY => $freq, FILE_NUMBER => $fnum };

    Check out perldoc perldsc for more information.

    I also noticed that you have if ($fnum eq "") { my $fnum = "_001" }. You are declaring a new $fnum that can only be seen within the scope of the if. In other words, $fnum will still be "" when you construct your anonymous hash. Perhaps instead you should replace the entire if with $fnum = "_001" if $fnum eq "";. I hope this helps you with your problem.

      Ok, now I see what was happening. Thanks to you and the other responding monks. I was clobbering %rets by recreating it on each record instead of just letting it be autovivified.

      When I see it done right, the problem seems so clear.

      Thanks!++

Re: Hash of anonymous hashes --- Oh my
by Limbic~Region (Chancellor) on Nov 17, 2003 at 18:48 UTC
    sweetblood,
    Try the following untested code:
    #!/usr/bin/perl -w use strict; my %rets; open(RL, "/home/myftplog") or die "Unable to open input file : $!" my @fields = qw ( FNAME RECLEN LIAISON_EMAIL LIAISON_FNAME LIAISON_LNAME LIAISON_AREACODE LIAISON_PHONE LIAISON2_EMAIL LIAISON2_FNAME LIAISON2_LNAME LIAISON2_PHONE RETNAME RETAILER_EMAIL LIAISON2_AREACODE RETAILER2_EMAIL FTPCHECK RETID SCRIPT_NAME EXECFLAG FREQUENCY FILE_NUMBER ); while (<RL>) { chomp; next if /^$/; my @vals = split /:/; $vals[0] ||= '_001'; my %temp_hash; @temp_hash{ @fields } = @vals; $hash{ $vals[0] } = \%temp_hash; } print $_, $/ for keys %rets;
    Cheers - L~R
        allolex,
        I would also suggest to sweetblood that he might consider leaving the values in an an AoA,

        I didn't suggest an AoA, but rather, a HoH as requested. I just use a hash slice to make the code a lot more concise.

        Cheers - L~R

A reply falls below the community's threshold of quality. You may see it by logging in.