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

I have a hash with entries composed of records as illustrated in the following:

$record = { EMPLOYER => "company name", EMPLOYEES => ["john", "fred", ...], EMPLOYEES_FAMILY_MEMBERS => {"susan", "bill"}, };

The hash key is the EMPLOYER (i.e.,)

%CompanyInfo{ $record->{EMPLOYER} } = $record;

I want to find all records (by key) that have

EMPLOYEES =~ m/jim/ and EMPLOYEES_FAMILY_MEMBERS =~ m/bill/.

Is there a way to do this w/o a loop? Using grep?

I can search the keys using:

@employer = grep{$_ =~ m/Name/} keys %CompanyInfo;

I don't know how to perform this type of search "deeper into the hash" (e.g., with arrays or hashes within the $CompanyInfo hash).

Thanks

Replies are listed 'Best First'.
Re: Searching hashes of hashes ...
by ikegami (Patriarch) on Oct 15, 2007 at 19:29 UTC

    You can't do what you want without looping, since every key needs to be visited. In fact, you need three loops.

    for every company for every employee of the company for every family member of the company

    But yes, you can use grep to loop.

    my @companies = grep { grep { $_ eq 'jim' } @{$_->{EMPLOYEES}} && grep { $_ eq 'bill' } @{$_->{FAMILY_MEMBERS}} } keys %CompanyInfo;
Re: Searching hashes of hashes ...
by GrandFather (Saint) on Oct 15, 2007 at 21:45 UTC

    Your data structure seems to be wrong. You show something that could be described as HoHoH, but I suspect you should really have a AoHoA. Consider:

    use strict; use warnings; my @records = ({ EMPLOYER => "Widget Co.", EMPLOYEES => "jim", EMPLOYEES_FAMILY_MEMBERS => ["susan", "bill"], }, { EMPLOYER => "Widget Co.", EMPLOYEES => "john", EMPLOYEES_FAMILY_MEMBERS => ["liz", "bill"], }, { EMPLOYER => "Foo Ltd.", EMPLOYEES => "jim", EMPLOYEES_FAMILY_MEMBERS => ["karen", "bob"], }, ); my @selected = grep { "@{$_->{EMPLOYEES_FAMILY_MEMBERS}}" =~ /bill/ } grep { $_->{EMPLOYEES} =~ /jim/ } @records; print "Found ", join (", ", map { $_->{EMPLOYER} } @selected), "\n";

    Prints:

    Found Widget Co.

    Perl is environmentally friendly - it saves trees
Re: Searching hashes of hashes ...
by lorn (Monk) on Oct 15, 2007 at 19:22 UTC

    I did not understand your indention, you need to use tags in your messages ;)

    i was try to understand your hash and i stoped here

    #!/usr/bin/perl use strict; use warnings; use Data::Dumper; my %hash = ( 'record' => { 'employees' => { 'foo' => 'lorn', 'bar' => 'perlmonks', 'quux' => 'lornlab', } } ); my $employees = $hash{record}->{employees}; foreach my $key ( keys %{ $employees } ) { if ( $key =~ /foo/ ) { print "$key - " , $employees->{$key}, "\n"; } if ( $key =~ /f\w{2}/ ) { print "$key - " , $employees->{$key}, "\n"; } }

    ....

    after a little help, with hash of the Articuno said: "this guy need a database simple, or not, like http://www.sqlite.org/ "

Re: Searching hashes of hashes ...
by naikonta (Curate) on Oct 16, 2007 at 01:27 UTC
    I think you need to store your data in a database. Flat database will do, but guessing on how you tried to create your hash, you'll get more benefits with relational one. If it comes from external source, there are some ways to structure the data in the program, but it depends on the format of that external source.

    Open source softwares? Share and enjoy. Make profit from them if you can. Yet, share and enjoy!

Re: Searching hashes of hashes ...
by chenho (Initiate) on Oct 24, 2007 at 19:20 UTC

    GrandFather - I changed my code to arrays of arrays ... and used your grep examples. Works great. Thanks for the help.

Re: Searching hashes of hashes ...
by princepawn (Parson) on Oct 25, 2007 at 15:37 UTC
    here is a related thread.


    Carter's compass: I know I'm on the right track when by deleting something, I'm adding functionality