TJ-47 has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I am new to perl programming and I am trying to figure out how to upda +te a hash in perl. I have the following file that I would like to rea +d line by line. OA322 U383 Mar 3.84 2.44 OA322 U982 Dec 2.57 1.83 OA322 U946 May 2.87 1.35 OA322 U823 Dec 6.61 4.08 OA322 U590 Aug 8.19 9.62 OA322 U19 Jul 9.93 9.23 BD110 U144 Apr 4.22 4.93 BD110 U848 Dec 1.72 7.30 BD110 U498 Jun 6.88 8.72 BD110 U606 Sep 5.54 9.86 BD110 U16 Jul 6.47 7.67 BD110 U160 Sep 7.21 4.12 BD110 U572 Jul 2.60 6.86 BD110 U804 Jul 0.04 9.71 RF858 U261 Jan 5.69 1.64 RF858 U731 Sep 9.45 7.13 RF858 U551 Jan 4.67 6.40 RF858 U888 Dec 7.22 4.20 VS524 U509 Jan 5.94 9.46 VS524 U14 Aug 5.22 1.78 MN739 U710 Jul 3.98 1.83 I would like to create a hash that looks like this. Given below is the + script. What is happening is that my hash only has the last line it +reads for each key. Appreciate any help !!
foreach (@new_line) { print $_, "\n"; my @ju = split ,@new_line; $self->{code}{$ju[0]} = { event => $ju[1], month => $ju[2], am => $ju[3], pm => $ju[4], } } print Dumper $self->{code}; } Output: $VAR1 = { 'MN739' => { 'am' => '3.98', 'event' => 'U710', 'month' => 'Jul', 'pm' => '1.83' }, 'RF858' => { 'event' => 'U888', 'am' => '7.22', 'pm' => '4.20', 'month' => 'Dec' }, 'VS524' => { 'month' => 'Aug', 'pm' => '1.78', 'am' => '5.22', 'event' => 'U14' }, 'BD110' => { 'event' => 'U804', 'am' => '0.04', 'pm' => '9.71', 'month' => 'Jul' }, 'OA322' => { 'month' => 'Jul', 'pm' => '9.23', 'am' => '9.93', 'event' => 'U19' } };

Replies are listed 'Best First'.
Re: Question on updating a hash table
by toolic (Bishop) on Mar 25, 2016 at 20:48 UTC
    I think you want to push:
    use warnings; use strict; use Data::Dumper; $Data::Dumper::Sortkeys=1; my %data; while (<DATA>) { chomp; my @ju = split; push @{ $data{$ju[0]} }, { event => $ju[1], month => $ju[2], am => $ju[3], pm => $ju[4], } } print Dumper(\%data); __DATA__ OA322 U383 Mar 3.84 2.44 OA322 U982 Dec 2.57 1.83 OA322 U946 May 2.87 1.35 OA322 U823 Dec 6.61 4.08 OA322 U590 Aug 8.19 9.62 OA322 U19 Jul 9.93 9.23 BD110 U144 Apr 4.22 4.93 BD110 U848 Dec 1.72 7.30 BD110 U498 Jun 6.88 8.72 BD110 U606 Sep 5.54 9.86 BD110 U16 Jul 6.47 7.67 BD110 U160 Sep 7.21 4.12 BD110 U572 Jul 2.60 6.86 BD110 U804 Jul 0.04 9.71 RF858 U261 Jan 5.69 1.64 RF858 U731 Sep 9.45 7.13 RF858 U551 Jan 4.67 6.40 RF858 U888 Dec 7.22 4.20 VS524 U509 Jan 5.94 9.46 VS524 U14 Aug 5.22 1.78 MN739 U710 Jul 3.98 1.83

    See also:

Re: Question on updating a hash table
by stevieb (Canon) on Mar 25, 2016 at 20:55 UTC

    You're relatively close, but remember hashes can only have one value per key name. What you want is to push the new hash reference into an array under the top level key name. Here's an example:

    while (<DATA>){ my @ju = split /\s+/, $_; push @{ $self->{code}{$ju[0]} }, { event => $ju[1], month => $ju[2], am => $ju[3], pm => $ju[4], }; } print Dumper $self->{code}; __END__ # trimmed down example output $VAR1 = { 'RF858' => [ { 'am' => '7.22', 'event' => 'U888', 'pm' => '4.20', 'month' => 'Dec' } ], 'VS524' => [ { 'am' => '5.94', 'month' => 'Jan', 'pm' => '9.46', 'event' => 'U509' }, { 'am' => '5.22', 'month' => 'Aug', 'pm' => '1.78', 'event' => 'U14' } ], };

    Here's one way that describes how to access all portions of the struct

    for my $top_key (keys %{ $self->{code} }){ print "$top_key\n"; for my $href (@{ $self->{code}{$top_key} }){ for (keys %$href){ print "\t$_ => $href->{$_}\n"; } print "\n"; } }
      Thanks a lot !!
Re: Question on updating a hash table
by Marshall (Canon) on Mar 25, 2016 at 21:58 UTC
    The general issue here is that you need a more advanced structure than a simple hash because a simple hash can only have one value for each key. Perl data structures from perldoc may be helpful to you in understanding the code other monks have posted. You need a "Hash of array of Hashes". The code that other Monks have posted does work, but to understand why it works, read the link as a starting place.

    update: My latest motto (modern version of "give a man a fish"):
    Give a man a gun and he can rob a bank. Teach a man to be a banker and he can rob the world.

    Not meant as a overt political statement although it is intended to be humorous. It is important to understand why the code works so that you can extend it and use it in other situations.