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

Hi, I am currently working on my first perl program. Which would make this my first post here at perlmonks so take it easy on me :P

I am stuck on attempting to make an array of hashes, where each hash has both arrays(of scalars) and scalars within it. There error I am currently getting is:

Can't coerce array into hash at calcoverlap.pl line 222.

1 is {

here is where I set up the hash:
%imolecule = ( 'maxval' => [@maxval], 'minval' => [@minval], 'range' => [@mp], 'label' => $molcount, 'peers' => '0', ); push @allmolecules, %imolecule;
this part gets looped for as many times as there are molecules in a file. I reuse the '%imolecule' hash each loop, clearing it and refilling it with data. At the end of the loop I try to print out the hash array to see if it worked at all:
for $i ( 1 .. $#allmolecules ) { print "$i is { "; for $field ( keys %{ $allmolecules[$i] } ) { #line 222 if (ref($allmolecules[$i]{$field}) eq "ARRAY") { print "$field=@{$allmolecules[$i]{$field}}"; } else { print "$field=$allmolecules[$i]{$field}"; } } print "}\n"; }
The above error indicates that the problem lies with this line of code:
for $field ( keys %{ $allmolecules[$i] } ) {
which would mean the allmolecules[i] isn't a hash.

Does anyone know what my mistake would be?

Also, since I reuse the imolecule hash each loop, I can't push it as a reference, but is there a better way to be doing it?

Appreciate any help :)

-tom

Update: Wow, thanks for the quick responses. I didn't realize that using {} would allocate new memory for my hash each round, allowing me to use the same hash name each loop. Dumper was very useful for me as well. I will definitely read that suggested material so my next problem won't be so easy for you guys to solve ;). Thanks again :)

Replies are listed 'Best First'.
Re: Help creating/printing array of hashes
by AR (Friar) on May 27, 2010 at 15:53 UTC

    Hi Tom.

    When working with complicated data structures, one of your best debugging friends is Data::Dumper (and related modules, your preference may vary). Print out a ref of your data structure to see if you understand how you're filling it.

    use Data::Dumper; print Dumper(\@allmolecules);

    Edit: You also might want to take a look into references, possibly in our tutorial section. Pushing an entire hash into an array makes sense in your head, but you want to push the reference to the hash to get the behavior you're expecting.

Re: Help creating/printing array of hashes
by toolic (Bishop) on May 27, 2010 at 16:00 UTC
    push @allmolecules, %imolecule;
    I suspect the above line is not what you want to do. The 1st element of the allmolecules array is a key of the imolecule hash. The 2nd element of the array is a value of the hash. The 3rd element of the array is a key of the hash, etc. So, as you loop through the array, $allmolecules[$i] alternates between being a simple scalar and a reference to an array; it will never be a reference to a hash because %imolecule does not contain any hash references as its keys or values.

    To debug, I like to reduce my code as much as possible, then print data structures, as follows:

    use strict; use warnings; use Data::Dumper; my @maxval = 0 .. 4; my %imolecule = ( 'maxval' => [@maxval], 'peers' => '0', ); my @allmolecules; push @allmolecules, %imolecule; print Dumper(\@allmolecules); __END__ $VAR1 = [ 'maxval', [ 0, 1, 2, 3, 4 ], 'peers', '0' ];

    See also Basic debugging checklist and perldsc.

    I can not reproduce your exact error message. If you can reduce your code to a smaller size and make it self-contained so that anyone can run it, then we should be able to give you better advice. Remember to use strict and warnings.

Re: Help creating/printing array of hashes
by NetWallah (Canon) on May 27, 2010 at 17:43 UTC
    That is impressively complex for a "first perl program"!.

    Others have directed you toward debugging (push a hashref into the array, instead of hash).

    This note focuses more on perl STYLE - in particular, your use of c-style loops, which, although usable, are better written "perl style". Your loop:

    for $i ( 1 .. $#allmolecules ) { ...
    could be re-coded (untested) as:
    for my $currentMolecule ( @allmolecules ) { ... while (my ($key,$val) = each %$currentMolecule ) { #line 222 if (ref($val) eq "ARRAY") { print "$key=@$val"; } else { print "$key=$val"; } ... } }
    Note the use of "my" to localize the scope of temporary variables.
    update: Changed inner "for" loop into a "while (my ($k,$v)=each.." loop after I noticed the O.P. needed both the key AND the value.

         Syntactic sugar causes cancer of the semicolon.        --Alan Perlis

Re: Help creating/printing array of hashes
by Marshall (Canon) on May 27, 2010 at 17:17 UTC
    To allocate new memory for the hash, this is similar to what you did for the arrays ie , {%imolecule}.
    %imolecule = ( 'maxval' => [@maxval], 'minval' => [@minval], 'range' => [@mp], 'label' => $molcount, 'peers' => '0', ); push @allmolecules, {%imolecule};
    Update: So some example code for you... This is an Array of Hash (AoH). You were on the right track realizing that you can't just push a ref to %imolecule. [@maxval] expands @maxval and then puts it into a new hunk memory that is an anonymous array (i.e. makes a "deep" copy). The hash can be handled in the same way. Any way, you can have a "molecule template" that you fill out and then push onto @allmolecules.
Re: Help creating/printing array of hashes
by planetscape (Chancellor) on May 27, 2010 at 21:48 UTC