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

I'm attempting to build the data structure shown below that will be passed to a nested LOOP in HTML::Template.
$OUTER_Ref = [ { 'INNER' => [ { 'DATA' => 'data01' }, { 'DATA' => 'data02' }, ] }, { 'INNER' => [ { 'DATA' => 'data11' }, { 'DATA' => 'data12' }, ] }, ];
I can up with this simplfied snippet to build the structure but I'm getting an unexpected reference to an undefined value and it's not getting all the values.
use strict; use Data::Dumper; my @outer = (); my @inner = (); my $n = 0; while (<DATA>) { chomp; push @inner, { DATA => $_ }; if ($n == 1) { push @outer, { 'INNER' => @inner }; @inner = (); $n = 0; } else { $n++; } } print Dumper(\@outer); __DATA__ data01 data02 data11 data12

Replies are listed 'Best First'.
Re: Nested LOOP in HTML::Template
by bmann (Priest) on May 10, 2005 at 23:41 UTC
    You want the hash element to be an array of hashes. Use [] to create an anonymous arrayref of hashes out of @inner, then push onto @outer.

    use strict; use Data::Dumper; my @outer = (); my @inner = (); my $n = 0; while (<DATA>) { chomp; push @inner, { DATA => $_ }; if ($n == 1) { # here --------------v v push @outer, { 'INNER' => [ @inner ] }; @inner = (); $n = 0; } else { $n++; } } print Dumper(\@outer); __DATA__ data01 data02 data11 data12
    Output:
Re: Nested LOOP in HTML::Template
by moot (Chaplain) on May 10, 2005 at 22:25 UTC
    You probably want this line:
    push @outer, { 'INNER' => @inner };
    to be this:
    push @outer, { 'INNER' => \@inner };
    otherwise you are setting the value of the INNER key to a scalar - the size of the @inner array.

    You'll also want to declare the @inner inside the while() loop, otherwise you'll find that each INNER's value holds the same data.

      I tried that but the @inner array gets cleared within the if statement and the reference now points to an empty array. However, having messed with this most of the afternoon, I came up with this that seems to work.

      Making $inner a ref to an array and de-referencing for the push seems to solve the problem.

      my @outer = (); my $inner = []; my $n = 0; while (<DATA>) { chomp; push @$inner, { DATA => $_ }; if ($n == 1) { push @outer, { INNER => $inner }; $inner = []; $n = 0; } else { $n++; } }
Re: Nested LOOP in HTML::Template
by shemp (Deacon) on May 10, 2005 at 22:27 UTC
    I havent fully analyzed your code, but one problem is when you're pushing onto outer, your anonymous hashref value is attempting to be an array, but hash values cant be arrays, they can be arrayrefs, like this:
    push @outer, { 'INNER' => \@inner };
    The way that you have it, i believe that @inner will be taken in scalar context which will evaluate to the number of elements in inner.

    But, when you then do

    @inner = ();
    that will also re-initialize the reference in the value pointed to by 'INNER', because thats a ref to @inner.

    UPDATE: Forget about this part, i missed the part about resetting $n = 0;
    I think that overall, you need to redefine your problem, because you only have 1 loop, and you want to build a 2 level structure. Also, your if ( $n == 1 ) clause will only be true once (on the second iteration), so only 1 thing will get pushed onto @outer.