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

Hello,
I have the following question:
there are three values: masterid, attribute_id, attribute_value. each masterid, can have multiple attributes. consider the code:
my $attr_detail = $dbh->prepare("select pa.masterid,pa.pco_attribute_id,pa.pco_v +alue from attributes_short pa, pageids p, prodpg pg where p.page_id=pg.page_id and pg.masterid=pa.masterid;"); + + my (%details, $m_id, $attr_id); $attr_detail->execute(); while (my $r = $attr_detail->fetchrow_hashref()) { $m_id = $r->{'masterid'}; $attr_id = $r->{'pco_attribute_id'}; # $details{$m_id}{pco_attribute_id} = $r->{'pco_attribut +e_id'}; $details{$m_id,$attr_id}{pco_value} = $r->{'pco_value' +}; } + + open (DETAILS,">>attr_detail.tsv"); foreach $m_id (keys %details) { print DETAILS "$m_id\t$attr_id\t$details{$m_id,$attr_id}\n"; } close DETAILS;
i need to use a multipatrt key in (masterid,attribute_id) to to get complete data, i'm not sure how to use foreach in this case. please help
moochos grassy ass:
~vili

thanks for everyones kind reply. 'twas most halpful. reading up on HoH, and hashref.

Replies are listed 'Best First'.
Re: multipart key in hash, i'm confused
by Zed_Lopez (Chaplain) on Jan 19, 2004 at 20:28 UTC

    perldoc perlreftut

    One way to do this is a hashref of hashrefs:

    while (my $r = $attr_detail->fetchrow_hashref()) { $details->{$r->{'masterid'}}->{$r->{pco_attribute_id'}}->{pco_value} + = $r->{'pco_value'}; } # ... while (my ($master_id, $attr_ref) = each %details) { while (my ($attr_id, $pco_value) = each %$attr_ref) { print DETAILS "$master_id\t$attr_id\t$pco_value\n"; } }

    Using a multipart key was much-used in Perl 4 and has largely fallen out of fashion since we've had the option of using references to make multi-dimensional hashes. I think it can still be a pretty good approach to some cases when you're guaranteed the keys won't have binary values (or, more specifially, won't contain $;). The downside is that you often need to go out of your way to split the key, as below:

    for my $m_id_attr_id (keys %details) { my ($m_id, $attr_id) = split $;, $m_id_attr_id; print DETAILS "$m_id\t$attr_id\t$details{$m_id_attr_id}\n"; }

    or, shorter:

    print DETAILS (join "\t", split $;, $details{$_}), "\n" for keys %details;

    (Code untested.)

Re: multipart key in hash, i'm confused
by tadman (Prior) on Jan 19, 2004 at 20:28 UTC
    If you have a hash of hashes (HoH), such as you have here, then you need to recurse through each level accordingly. The comma separator won't cut it. Here's a quick reference:
    foreach my $key (keys %hash) { foreach my $subkey (keys %{$hash{$key}}) { print "$key,$subkey => $hash{$key}{$subkey}\n"; } }
    This presumes you have a pure HoH structure, which is a fairly safe assumption if you've created it yourself. Note that in the second foreach you're casting the hash entry $hash{$key} as a hash itself so you can access the keys and iterate through this second layer.
Re: multipart key in hash, i'm confused
by The Mad Hatter (Priest) on Jan 19, 2004 at 20:38 UTC
    Like the others have said, a HoH structure will work. (There are others, but that is probably the best.) If you have trouble wrapping your head around how this structure "looks", try using Data::Dumper:
    use Data::Dumper; print Dumper(\%details), "\n";