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

I have a HoH that looks like this (I can change it):
use strict; use warnings; my %hoh = ( pc1 => { os => "win32", user => "dave"}, pc2 => { os => "linux", user => "john"}, pc3 => { os => "win32", user => "robin"} );
I want to find the linux users, and later I'll want find dave's PCs. The HoH will be much bigger and so I don't want to do an iterative search. Maybe a database would be better. I've heard of an in-memory SQL one with a module on CPAN, but I cannot remember the name or find it.

Any ideas?

--traveler

Replies are listed 'Best First'.
Re: HoH search question
by BrowserUk (Patriarch) on Sep 25, 2003 at 20:42 UTC

    Personally, I would say that you are using the wrong data structures. The keys of you primary hash are 'pc' + n. The pc part is repetative and reduntant. Your left with n, which gives you an array.

    In you secondary hashes, your keys are all identical and only the values vary. The greatest benefit of a hash is the ability to look things up by name, but your not able to use this effectively. All your keys are again, repetative and redundant.

    I think I would use something like this.

    #! perl -slw use strict; my( %users, @linux, @win32 ); my @pcs = ( [ 'win32', 'dave' ], [ 'linux', 'john' ], [ 'win32', 'robin' ], ); for( 0 .. $#pcs ) { my $pc = $pcs[ $_ ]; $users{ $pc->[1] } = $_; push @{ $pc->[0] eq 'linux' ? \@linux : \@win32 }, $_; } print 'Linux users: ', join ' ' , map{ $_->[1] } @pcs[ @linux ]; print "Dave's pc is number $users{ dave } attributes:" , join ' ', @{ $pcs[ $users{ dave } ] }; print "Win32 pc numbers: @win32\n\t" , join "\n\t", map{ join ':', @$_ } @pcs[ @win32 ]; __END__ Linux users: john Dave's pc is number 0 attributes:win32 dave Win32 pc numbers: 0 2 win32:dave win32:robin

    This scheme allows you to answer all of the questions you mentioned using direct or 1 level indirected indexing with no searching.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
    If I understand your problem, I can solve it! Of course, the same can be said for you.

Re: HoH search question
by stajich (Chaplain) on Sep 25, 2003 at 18:25 UTC
    Seems like you need to construct a second hash which is indexed on the fields you want if you don't want to do this iteratively. You'd need to construct it either by iterating through your current data structure once or at the same time you build this. For example
    my %oslookup; while( my ($pc,$data) = each %hoh ) { push @{ $oslookup{$data->{'os'}} }, $pc; } # later on print "linux pcs are: ", join(',', @{$oslookup{'linux'} || []}, "\n";
    Similarly a second hash for the 'user' field. If you expect to have a lot of keys for each record, with a little creativity you can build a single index hash which has lookups for all the keys in your data structure. When/If this gets really big you might want to change to using a DB structure - either RDBMS or as I prefer DB_File. You'll probably want to use the B-Tree implementation to store multiple values for a key.
Re: HoH search question
by jdtoronto (Prior) on Sep 25, 2003 at 18:42 UTC
    ou could try DBD::CSV or DBD::Sprite or DBD::RAM or DBD::AnyData - all of which use files or RAM in the obvious case under the DBI/DBD paradigm.

    jdtoronto