in reply to Finding hashes in hashes of hashes

cyphy, you got homework to do over Christmas break?
Bummer!

Update: Anyway, here's my approach. Note that I do not die in the extraction function on zero members; I feel this sort of thing should be left to the caller. (Note: Older versions of Test::More don't have note.)

>perl -wMstrict -le "my %families = ( flintstones => { dad => 'fred', mom => 'wilma', kid => 'bambam', }, simpsons => { dad => 'fred', mom => 'marge', kid => 'bart', sis => 'lisa', }, ); use Test::More 'no_plan'; my @got; is @got = get_members(\%families => kid => 'bart'), 1, 'got bart'; note qq{families with bart: '@got'}; is @got = get_members(\%families => dad => 'fred'), 2, 'got freds'; note qq{families with freds: '@got'}; is @got = get_members(\%families => mom => 'june'), 0, 'no junes'; note qq{families with june: '@got'}; is @got = get_members(\%families => sis => 'lisa'), 1, 'got lisa'; note qq{families with lisa: '@got'}; is @got = get_members(\%families => xxx => 'yyy'), 0, 'no xxx'; note qq{what's an xxx? '@got'}; sub get_members { my ($hr_families, $member, $name) = @_; return grep $hr_families->{$_}{$member} eq $name, grep exists($hr_families->{$_}{$member}), keys %$hr_families ; } " ok 1 - got bart # families with bart: 'simpsons' ok 2 - got freds # families with freds: 'simpsons flintstones' ok 3 - no junes # families with june: '' ok 4 - got lisa # families with lisa: 'simpsons' ok 5 - no xxx # what's an xxx? '' 1..5

Also: Noticed that undefined family members would generate 'Uninitialized ...' warnings; fixed. (The two grep statements could be combined into one.)

Replies are listed 'Best First'.
Re^2: Finding hashes in hashes of hashes
by cyphy (Initiate) on Dec 28, 2009 at 17:53 UTC
    Thanks for you answer. It solves my problem! No, it is not my homework (got something else). I'm just trying to create a script where I need something similar (no families and no flinstones ;). I didn't want to write the full code, since I only need this in a single sub. I am using strict, warnings, diagnostics and even perlcritic (cruel). I played around with something like this:
    get_family_member('bart',$families); sub get_family_member { my @args = @_; my $who = shift @args; my $families = shift @args; foreach my $family (%families) { if ($families->{$family}->{kid} eq "bart") { return $dfamilies->{$family}->{kid}; last; } } }
    but where would I say, it should die, when 'bart' is not found? It has been a while since I used perl the last time. I returned, because I missed the nice community and CPAN. However, since I used some more exotic languages (far away from C-like styles and paradigms) I guess I need to rewire my brain. I hope I remember correctly, how Perls scopes and datatypes work. Maybe I should just try to find my old perl books.

      The 'die' would go after the foreach (refer to the pseudocode that I posted). Note the comments below:

      sub get_family_member { my @args = @_; my $who = shift @args; # <-- this var is not used my $families = shift @args; foreach my $family (%families) { if ($families->{$family}->{kid} eq "bart") { # <-- are you sure yo +u want to hard-code 'bart'? I think you need $who return $dfamilies->{$family}->{kid}; # <-- typo in hash name last; # <-- this will never be reached since it already returned } } # no matches found: die here }

        bobf is quite right: the statements
            my @args = @_;
            my $who = shift @args;
            my $families = shift @args;
        are much better written as
            my ($who, $families) = @_;

        Also,  $families in the above example seems to be a hash reference,
        so use  %$families to dereference.

        Further,
            for my $family (%$families) { ... }
        won't do what you want; use
            for my $family (keys %$families) { ... }
        to iterate over the keys of the referenced hash.

        Thank you! About the typo and the who.. This is what happens, when you try to change your code to only reflect relevant parts. Next time I'll simply copy it.