Search code examples
perlhashiteratorperl-data-structures

Iterating over a complex data structure


I have what appears to be a hash of a hash of an array of hashes. I'm trying to pull some values out and I'm stumped (this is way deeper than I would go with a structure. It looks like this.....

%htest = (
  8569 => {
    4587 => [
           {
            date=> "2011-01-15",
            approved=> 1,
           },
           { 
            date=> "2011-01-12",
            approved=> 1,
           },
           ],
    1254 => [
           {
            date=> "2011-01-12",
            approved=> "",
           },
           { 
            date=> "",
            approved=> 1,
           },
           ],
        },
);

Trying to iterate over this thing is giving me a massive headache. I'm trying to access the number of elements under the second hash value (4587 and 1254). The number of those elements where approved="1" and the number of elements where the date contains a value.

If I could iterate over them I sure I could shove what I need into a less complex structure but so far I'm at a loss.

I got this far...

while (my ($id, $surveyhash) = each %{ $htest{'8569'} } ){
    print "$enumid = $subhash\n";
    print Dumper $subhash."\n";
}

That gives me the "4587" and "1254" but trying to do a dumper on $subhash just gives me....

4587 = ARRAY(0x9a9ffb0)
$VAR1 = 'ARRAY(0x9a9ffb0)
';
1254 = ARRAY(0x9a91788)
$VAR1 = 'ARRAY(0x9a91788)
';

Any idea how to iterate over this monstrosity? Janie


Solution

  • Your structure has typos, you need commas between the innermost hashes and a parenthesis at the end (rather than a curly bracket)

    Once you fix it you can use something like this:

    my $approved = 0, my $date_has_value = 0;
    while ( my ($k,$vref) = each %htest ) {
        while ( my ($k,$v) = each %$vref ) { 
            # Now you're inside the inner hash, so there will be 2 iterations
            # with $k 4587 and 1254
            foreach my $item (@$v) {
                # Now each $item is a reference to the innermost hashes
                $approved++ if $item->{approved} == 1;
                $date_has_value++ if $item->{date};
            }
        }
    }