http://qs321.pair.com?node_id=340027

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

Monks
I have an inventory (textfile) with the following:
Category ID Name Type Size
=======================================
WaterSports 8765 Drysuit r M-L
WaterSports 8365 Paddle t 45

WinterSports 5231 Snowboard j 85
WinterSports 5281 Gloves r S
Etc..
I want to create a hash of hashes like the following
$VAR1 = { 'WaterSports' => [ '8765', [ 'Drysuit', 'r', 'M-L' ] '8365', [ 'Paddle', 't', '45' ] ] };
But instead my code is creating this, what is wrong?
$VAR1 = { 'WaterSports' => [ '8765', [ 'Drysuit', 'r', 'M-L' ] }; $VAR1 = { 'WaterSports'=> [ '8365', [ 'Paddle', 't', '45' ] ] };
This is my code:
open(INFILE, "products-id.txt")|| die "Cannot open products-id.txt fil +e"; open (OUTPUT,">$output") or die ("Can't open file $output $!"); chomp(my @ProductArray = map { /^\s*$/ ? () : $_ } <INFILE>); close (INFILE); foreach my $line(@ProductArray) { my ($Category, $ID, $Name, $Type, $Size) = split( / /, $line ); %AllProducts = ($Category => [$ID, [$Name, $Type, $Size]]); print OUTPUT Dumper(\%AllProducts); }
Thanks is advance!!

Replies are listed 'Best First'.
Re: Different hashes?
by Fletch (Bishop) on Mar 26, 2004 at 14:58 UTC

    You're clearing out the entire hash each time through the loop and replacing it with new contents. You want push @{ $AllProducts{ $Category } }, [ $ID, [ $Name, $Type, $Size ] ]. See perldoc perlreftut, perldoc perldsc, and perldoc perllol.

      Fletch and borisz:
      the outer array referencing brackets [ ] are still wrong, take them away and you got it right.

        Actually what he probably really wants is a HOH and should be doing something like:

        $AllProducts{ $Category }->{ $ID } = { name => $Name, type => $Type, s +ize => $Size };

        But that's why he should read perldoc perldsc.

Re: Different hashes?
by tcf22 (Priest) on Mar 26, 2004 at 15:04 UTC
    You are overwriteing the key in %AllProducts every loop. You need to make the hash value an array ref then push onto it.

    Try this:
    foreach my $line(@ProductArray) { my ($Category, $ID, $Name, $Type, $Size) = split( / /, $line ); unless(exists $AllProducts{$Category}){ $AllProducts{$Category} = []; } push(@{$AllProducts{$Category}}, $ID, [$Name, $Type, $Size]); print OUTPUT Dumper(\%AllProducts); }

    - Tom

Re: Different hashes?
by borisz (Canon) on Mar 26, 2004 at 15:07 UTC
    #!/usr/bin/perl use Data::Dumper; my %products; while (defined( $_ = <DATA> )){ next if $. <= 2 || /^\s*$/; my @d = split ' '; my $cat = shift @d; my $id = shift @d; push @{$products{$cat}}, [ $id, \@d ]; } print Dumper(\%products); __DATA__ Category ID Name Type Size ======================================= WaterSports 8765 Drysuit r M-L WaterSports 8365 Paddle t 45 WinterSports 5231 Snowboard j 85 WinterSports 5281 Gloves r S
    Boris
Re: Different hashes?
by Happy-the-monk (Canon) on Mar 26, 2004 at 15:03 UTC

    Make the following change to your code:

    -    %AllProducts = ($Category => [$ID, [$Name, $Type, $Size]]);
    +    push @{ AllProducts{$Category} }, ( $ID, [$Name, $Type, $Size] );

    what was wrong?

    1. redefined the hash while looping, thus overwriting it.
    2. made a new array reference instead of pushing onto it.

    Cheers, Sören

Re: Different hashes?
by Anonymous Monk on Mar 26, 2004 at 15:36 UTC
    Thank you Monks and thanks for you comments!! It is working now :)
Different hashes part II
by Anonymous Monk on Mar 26, 2004 at 16:29 UTC
    Hello Monks I just send a message not long ago (different hashes?), and I tried your suggestions. I thought it was working because I run the script with a small textfile, but it is not!! :(
    It is creating a new hash, adding a new record at the time. it's exponential huge
    $VAR1 = { 'WaterSports' => [ '8765', [ 'Drysuit', 'r', 'M-L' ] }; $VAR1 = { 'WaterSports'=> [ '8765', [ 'Drysuit', 'r', 'M-L' ] '8365', [ 'Paddle', 't', '45' ] ] };
    This is my modify code:
    open(INFILE, "products-id.txt")|| die "Cannot open products-id.txt fil +e"; open (OUTPUT,">$output") or die ("Can't open file $output $!"); chomp(my @ProductArray = map { /^\s*$/ ? () : $_ } <INFILE>); close (INFILE); foreach my $line(@ProductArray) { my ($Category, $ID, $Name, $Type, $Size) = split( / /, $line ); push(@{$AllProducts{$Category}}, $ID, [$Name, $Type, $Size]); print OUTPUT Dumper(\%AllProducts); }
    I also tried this
    push @{$AllProducts{$Category}}, ($ID, [$Name, $Type, $Size]);
    Thanks
      I am trying borisz's solutions, but as well as the others it's taking too much time to execute, so I cancelled it.. but this time the PARTIAL output I am getting is OK, I am not sure it is repeating the whole thing over and over..
      Borisz's script: #!/usr/bin/perl use Data::Dumper; my %products; while (defined( $_ = <DATA> )){ next if $. <= 2 || /^\s*$/; my @d = split ' '; my $cat = shift @d; my $id = shift @d; push @{$products{$cat}}, [ $id, \@d ]; } print Dumper(\%products);
        It is OK, I should not print the dumper(\%product) to the output file, inside the loop mmmmmm sorry about that
      It might have been better to make this a reply or update to your earlier post. Since you seemed to have missed the point of advice that others gave there, I think I'll post a reply there myself, because more information is available there regarding the problem. (In fact, maybe the present thread should be "considered" for removal or relocation.)