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

Dear Masters,
Why my code below:
use strict; use Data::Dumper; use Carp; my @nar = ( ['fact 1 - ParamGrp1', 'foo', 'bar'], ['fact 1 - ParamGrp2', 'qux', 'bom'], ['fact 1 - ParamGrp1', 'fuu', 'gong'], ['fact 2 - ParamGrp1', 'fiu', 'ging'], ); my %hash; my %param_hash; foreach my $nar (@nar) { my ( $cwd, $prm ) = split( " - ", $nar->[0] ); my @rest = @{$nar}[ 1 .. @{$nar} - 1 ]; push @{ $param_hash{$prm} }, [@rest]; $hash{$cwd} = {%param_hash}; } print Dumper \%hash ;
doesn't produce the following desired result:
$VAR1 = { 'fact 1' => { 'ParamGrp2' => [ [ 'qux', 'bom' ] ], 'ParamGrp1' => [ [ 'foo', 'bar' ], [ 'fuu', 'gong' ] ] }, 'fact 2' => { 'ParamGrp1' => [ [ 'fiu', 'ging' ] ] } };


---
neversaint and everlastingly indebted.......

Replies are listed 'Best First'.
Re: Constructing HoHoA from AoA
by Limbic~Region (Chancellor) on Jan 02, 2006 at 05:16 UTC
    neversaint,
    The following code does what you want
    #!/usr/bin/perl use strict; use warnings; use Data::Dumper; my @nar = ( ['fact 1 - ParamGrp1', 'foo', 'bar'], ['fact 1 - ParamGrp2', 'qux', 'bom'], ['fact 1 - ParamGrp1', 'fuu', 'gong'], ['fact 2 - ParamGrp1', 'fiu', 'ging'], ); my %data; for my $elem ( @nar ) { my ($key, @val) = @$elem; my ($key_1, $key_2) = split " - ", $key; push @{ $data{$key_1}{$key_2} }, [ @val ]; } print Dumper(\%data);
    It has been over 3 weeks since I have written a single line of code so please forgive me for posting a working solution without really answering the question being asked.

    Cheers - L~R

      Limbic~Region nailed it, I took your hash and your desired hash, wrote my own little loop and lo and behold, i got the same code. (hey that rhymed!)

      so since it's the same no need to post it...


      It's not what you look like, when you're doin' what you’re doin'.
      It's what you’re doin' when you’re doin' what you look like you’re doin'!
           - Charles Wright & the Watts 103rd Street Rhythm Band
Re: Constructing HoHoA from AoA
by parv (Parson) on Jan 02, 2006 at 05:51 UTC
    The reason for NOT getting the output that you want -- IOW, both $hash{'fact 1'} and $hash{'fact 2'} get the same contents in hash references -- is that %param_hash is sticky in your loop. During the looping, you keep filling the %param_hash, which you assign to any key in %hash.
Re: Constructing HoHoA from AoA
by holli (Abbot) on Jan 02, 2006 at 10:57 UTC
    The idea (borrowed) here is that transforming the array before processing it makes the alghorithm itself simpler.
    my %hash; for ( map { [ split (/ - /, $_->[0]), [@{$_}[1..$#_]] ] } @nar ) { push @{$hash{$_->[0]}->{$_->[1]}}, $_->[2]; } print Dumper \%hash ;
    Output:
    $VAR1 = { 'fact 2' => { 'ParamGrp1' => [ [ 'fiu', 'xxx' ] ] }, 'fact 1' => { 'ParamGrp2' => [ [ 'qux', 'bom' ] ], 'ParamGrp1' => [ [ 'foo', 'bar' ], [ 'fuu', 'gong' ] ] } };
    Update:
    fixed typo pointed out by jdalbec


    holli, /regexed monk/
Re: Constructing HoHoA from AoA
by Anonymous Monk on Jan 02, 2006 at 06:42 UTC
    It looks like you are over-thinking the algorithm. :-)
    my %hash; for my $nar ( @nar ) { my ( $key1, $key2 ) = split /\s*-\s*/, shift @$nar; push @{ $hash{ $key1 }{ $key2 } }, $nar; }
      Anonymous Monk,
      Or perhaps not. The question doesn't go into specifics of the rest of the code so your solution could be a problem for the following reasons:
      • /\s*-\s*/ will match a single dash anywhere it appears as * means 0 or more'
      • shift @$nar is destructive
      • push @{ $hash{ $key1 }{ $key2 } }, $nar; will push a reference to the original not a copy so there could be spooky action at a distance depending on the rest of the code

      Cheers - L~R

Re: Constructing HoHoA from AoA
by tphyahoo (Vicar) on Jan 02, 2006 at 15:36 UTC
    Well, here's what I came up with when I tried to solve it myself without looking at the other answers first. Not that innovative, but I will observe, for me at least, it seems to be easier to deal with hash refs and array refs than hash/arrays. Why this seems cleaner? I'm not sure if this is a syntactical thing or psychological thing, or a little of both, or just a quirk of mine, but at any rate:
    my $param_hash; foreach my $nar (@nar) { my ( $cwd, $prm ) = split( " - ", $nar->[0] ); my $rest = [ @$nar[ 1 .. 2 ] ]; push @{ $param_hash->{$cwd}->{$prm} }, $rest; } print Dumper $param_hash;
    I would also like to ask neversaint, did you clean up the D::D output, or did it really come out like that? I tried $Data::Dumper::Indent = 0, but everything just spewed out on one line. Indent = 1 or more, and it split over too many lines, like in holli's output above. So, if there's a way to do this, please share. Thanks!