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

I'm writing code for a nested template loop using HTML::Template. I have an array of hashes for the first loop, and then within each hash, I need to create a key (named picorder) whose value is another hash for the internal template loop.
Here is relevant code:
my $x=0; my $numpix = @data; while ($data[$x]){ my ($i,@orderdata,%myhash); foreach $i (1 .. $x){ if ($i == $data[$x]{'picorder'}){$myhash{'orderline'} = "< +option value=\"$i\" selected>$i</option>"; }else{$myhash{'orderline'} = "<option value=\"$i\" sel +ected>$i</option>";} push (@orderdata, \%myhash); } $data[$x]{'orderdata'} = \@orderdata; if ($data[$x]{'anaglyph'} eq "Yes"){$data[$x]{'anaglyph'}="che +cked";} $x++; }
When I run the program, I get the error 'Can't use string ("anaglyph") as a HASH ref while "strict refs" in use'. Any help will be greatly appreciated.

Replies are listed 'Best First'.
Re: dereferencing hash within a hash within an array
by sauoq (Abbot) on Jan 10, 2003 at 23:12 UTC
    Any help will be greatly appreciated.

    I'll help format it so it is at least readable.

    my $x = 0; my $numpix = @data; while ($data[$x]) { my ($i, @orderdata, %myhash); foreach $i (1 .. $x) { if ($i == $data[$x]{'picorder'}) { $myhash{'orderline'} = "<option value=\"$i\" selected>$i</ +option>"; } else { $myhash{'orderline'} = "<option value=\"$i\" selected>$i</ +option>"; } push (@orderdata, \%myhash); } $data[$x]{'orderdata'} = \@orderdata; if ($data[$x]{'anaglyph'} eq "Yes") { $data[$x]{'anaglyph'} = "checked"; } $x++; }

    I don't see the error though.

    -sauoq
    "My two cents aren't worth a dime.";
    
Re: dereferencing hash within a hash within an array
by lpoht (Sexton) on Jan 11, 2003 at 01:58 UTC
    I figured out that I needed the entries in the first ("root") array to be hash references. Below is the code used to generate this array.
    while($db->FetchRow()){ my %hash = $db->DataHash(@$fields_ref); push (@data, \%hash); }
    Whereas it was before
    while($db->FetchRow()){ push (@data, $db->DataHash(@$fields_ref)); }

    The DataHash function returns a hash whose keys are field names (from the database) and whose values are the values of those fields on a specific row. I don't like defining %hash every time a new row is processed, but couldn't get any "one-liner" way of making it work. How might I go about writing the push line with $db->DataHash(@$fields_ref) treated as a hash reference. In case anyone's interested, I touched up the code I originally posted. There were a few minor mistakes which caused some confusion about my looping.
    while ($data[$x]){ my ($i,@orderdata,%myhash); foreach $i (1 .. $numpix){ if ($i == $data[$x]{'picorder'}){ $myhash{'orderline'} = "<option value=\"$i\" selected>$i</option>"; }else{ $myhash{'orderline'} = "<option value=\"$i\" selected>$i</option>";} push (@orderdata, \%myhash); } $data[$x]{'orderdata'} = \@orderdata; #transform anaglyph data for checkboxes if ($data[$x]{'anaglyph'} eq "Yes"){ $data[$x]{'anaglyph'}="checked";} $x++; }
    Everything seems to work. Thanks for your help
      concerning the one-liner, this should work:
      while($db->FetchRow()){ push @data, { $db->DataHash(@$fields_ref) }; }
      By using the curlies you are creating an anonymous hash reference out of the hash returned by the DataHash method which is directly pushed onto @data.

      -- Hofmator

Re: dereferencing hash within a hash within an array
by BrowserUk (Patriarch) on Jan 10, 2003 at 23:07 UTC

    Update:Ignore this! Its a complete red-herring bought about by brain-fade.

    if ($data[$x]->{'anaglyph'} eq "Yes"){ $data[$x]->{'anaglyph'}="checked"; }

    To clarify: If the array element $data[$x] contains a valid reference to a hash, then you need dereference that using -> to indicate that this is the case.


    Examine what is said, not who speaks.

    The 7th Rule of perl club is -- pearl clubs are easily damaged. Use a diamond club instead.

      To clarify: If the array element $data[$x] contains a valid reference to a hash, then you need dereference that using -> to indicate that this is the case.

      No, you don't need to do so.

      my %h = ( foo => 'bar' ); my @a = ( \%h ); print "worked fine\n" if $a[0]{foo} eq 'bar';

      You need to use the arrow when you are dealing directly with a scalar containing a reference rather than a nested one.

      my %h = ( foo => 'bar' ); my @a = ( \%h ); my $r = \@a; print $r->[0]{foo}, "\n"; # $r[0] won't work since @r doesn't exist.
      -sauoq
      "My two cents aren't worth a dime.";
      
Re: dereferencing hash within a hash within an array
by Mr. Muskrat (Canon) on Jan 10, 2003 at 23:07 UTC
    Looks like you need to rethink some things...

    You're looping $i 1 through $x but you're also incrementing $x! When will this loop ever end? (After carefully matching braces, I see that I was mistaken.)

    Your data structure is very complex. You're trying to create an Array of Hashes of Arrays of Hashes? Or am I reading this wrong?

      If I understand you correctly you expect
      my $x = 10; for my $i (1 .. $x) { $x = 1; print $i; }
      to execute only once. That would be the case if the above was equivalent to
      my $x = 10; for (my $i = 1; $i <= $x; $i++) { $x = 1; print $i; }
      , but it isn't. Recall that the non-C-style for (aka foreach) is a list iterator. 1 .. $x is a list. Compare with   my @foo = 1 .. $x; If you'd now do   foreach (@foo) { ... } you wouldn't expect foreach to act any differently upon modification of $x.

      (Afaik for (EXPR .. EXPR) is nowadays optimized to not build a list, but that's irrelevant from a language point of view.)

      Hope I've helped,
      ihb
      The final data structure is an array of hashes. In each hash is another array of hashes (each hash having only one key/value pair).