Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Hash Ref: Need to find out how many children I have :-)

by rupesh (Hermit)
on Dec 16, 2005 at 09:41 UTC ( #517186=perlquestion: print w/ replies, xml ) Need Help??
rupesh has asked for the wisdom of the Perl Monks concerning the following question:


Suppose a hash ref exists like this:
$hash->{Grand}->{Parent1}->{Child1}->{name}; $hash->{Grand}->{Parent1}->{Child1}->{age}; $hash->{Grand}->{Parent1}->{Child2}->{name}; $hash->{Grand}->{Parent1}->{Child2}->{age}; $hash->{Grand}->{Parent1}->{Child3}->{name}; $hash->{Grand}->{Parent1}->{Child3}->{age}; $hash->{Grand}->{Parent2}->{Child1}->{name}; $hash->{Grand}->{Parent2}->{Child1}->{age}; $hash->{Grand}->{Parent2}->{Child2}->{name}; ...
I need to loop through "Grand" and get the number of Parents; and for each Parent, get number of Children; and for each children, print their names and ages.
How do I do this?
The actual rows have further more levels. The key importance here is perfomance.


Thanks,
Rupesh.

Comment on Hash Ref: Need to find out how many children I have :-)
Download Code
Re: Hash Ref: Need to find out how many children I have :-)
by davido (Archbishop) on Dec 16, 2005 at 09:57 UTC

    Data::Walk will walk the structure easily for you, and by hand crafting a wanted() sub, you can set up counters for various depths.

    Or if you already have worked out how to walk the structure, remember that my $count = keys %{$hash};, or later my $count = keys %{$hash->{Group}} will return a count of the number of keys in a given level.


    Dave

Re: Hash Ref: Need to find out how many children I have :-)
by tirwhan (Abbot) on Dec 16, 2005 at 10:02 UTC

    Update: Oops, misread the question. Clearly not the answer.

    Update2: This should do it though :-)

    Something like this?

    use warnings; use strict; my %count; my $hash = {Grand => { Parent1 => {Child1 => { name => "me", age => 99 }, Child2 => { name => "you", age => 42 }, Child3 => { name => "she", age => 1 }}}}; recurse_or_count($hash->{Grand},"Grand"); sub recurse_or_count { my ($cur,$string)=@_; for my $elem (keys %$cur) { if (ref($cur->{$elem}) eq "HASH") { $count{$string}++; recurse_or_count ($cur->{$elem},$string."->$elem"); } else { $count{$string}->{$elem}=$cur->{$elem}; } } } for my $key (sort keys %count) { if (ref($count{$key}) eq "HASH") { for my $data (sort keys %{$count{$key}}) { print "$key has $data $count{$key}->{$data}\n"; } }else { my $child = $count{$key} > 1 ? "children" : "child"; print "$key has $count{$key} $child\n"; } } __OUTPUT__ Grand has 1 child Grand->Parent1 has 3 children Grand->Parent1->Child1 has age 99 Grand->Parent1->Child1 has name me Grand->Parent1->Child2 has age 42 Grand->Parent1->Child2 has name you Grand->Parent1->Child3 has age 1 Grand->Parent1->Child3 has name she

    Update3: and if you don't mind the child data being printed out before the child count, here's a more efficient version of that:

    use warnings; use strict; my %count; my $hash = {Grand => { Parent1 => {Child1 => { name => "me", age => 99 }, Child2 => { name => "you", age => 42 }, Child3 => { name => "she", age => 1 }}}}; recurse_or_count($hash->{Grand},"Grand"); sub recurse_or_count { my ($cur,$string)=@_; for my $elem (sort keys %$cur) { if (ref($cur->{$elem}) eq "HASH") { $count{$string}++; recurse_or_count ($cur->{$elem},$string."->$elem"); } else { print "$string has $elem $cur->{$elem}\n"; } } } for my $key (sort keys %count) { my $child = $count{$key} > 1 ? "children" : "child"; print "$key has $count{$key} $child\n"; } __OUTPUT__ Grand->Parent1->Child1 has age 99 Grand->Parent1->Child1 has name me Grand->Parent1->Child2 has age 42 Grand->Parent1->Child2 has name you Grand->Parent1->Child3 has age 1 Grand->Parent1->Child3 has name she Grand has 1 child Grand->Parent1 has 3 children

    Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it. -- Brian W. Kernighan
Re: Hash Ref: Need to find out how many children I have :-)
by davidrw (Prior) on Dec 16, 2005 at 13:43 UTC
    The actual rows have further more levels. The key importance here is perfomance.
    Can you put this all into a database? Once there, gets a lot easier (and faster if indexed/structured properly).
    users user_id first_name last_name user_age -- !!!! really should be stored as birthdate or birthyear parent_user_rlt parent_id child_id SELECT grand.user_id as grandparent_id, parent.user_id as parent_id, child.user_id as child_id, child.first_name as child_first, child_last_name as child_last FROM users as grand LEFT JOIN parent_user_rlt as g2p ON g2p.parent_id = grand.user_id LEFT JOIN users as parent ON parent.user_id = g2p.child_id LEFT JOIN parent_user_rlt as p2c ON p2c.parent_id = parent.user_id LEFT JOIN users as child ON child.user_id = g2p.child_id ;
    If you use that query to construct a temp table called "grandchildren", then your answers become things like:
    SELECT distinct parent_id FROM grandchildren; SELECT grandparent_id, count(distinct parent_id) FROM grandchildren +GROUP BY grandparent_id; SELECT grandparent_id, parent_id, count(*) as num_kids FROM grandchi +ldren GROUP BY grandparent_id, parent_id; SELECT child_id, child_first, child_last FROM grandchildren;

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://517186]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (12)
As of 2014-09-23 16:13 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (229 votes), past polls