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

Long time reader, first time caller here. My question is rather simple but for some reason me and the guys here at work cant quite get a satisfactory answer to this little problem. Here it is. I have a two level hash like so:
%connections{socket}{username} = "Bob";
Now the socket key is created whenever a new socket is created and can be any name what so ever. So i dont ever really know what it is. username is always constant. SO how would i go about getting the value of Socket if all i have is {Username} = "Bob";
Thank you for your time

Replies are listed 'Best First'.
Re: Accessing Multilevel Hash Values
by suaveant (Parson) on Apr 24, 2002 at 13:30 UTC
    The quickest way would be to have another hash, with a name to socket name lookup... i.e.
    $socket = 'socketa'; $connections{$socket} = {}; $connections{$socket}{name} = 'Bob'; $sockets{Bob} = $socket; #to access it $connections{$sockets{Bob}};
    Of course... if you are only going to be accessing sockets by the "name", then you should consider using that as the key and storing the socket key somewhere else. But that is if name will be the only way you key in.

    The other way is to write a for loop to iterate through the hash and find it

    my $socket; my $name = 'Bob'; for my $key (keys %connections) { if($connections{$key}{name} eq $name) { $socket = $_; last; } } print "$socket is the socket for $name\n";
    Also, when accessing a hash value you should prepend the hash with a $, not a %, as so:
    $connections{socket}{username} = "Bob";
    See Tye's References Quick Reference

                    - Ant
                    - Some of my best work - (1 2 3)

Re: Accessing Multilevel Hash Values
by perlplexer (Hermit) on Apr 24, 2002 at 13:27 UTC
    my $sock = undef; my $name = 'Bob'; foreach my $conn (keys %connections){ if ($connections{$conn}{'username'} eq $name){ $sock = $conn; last; } } if (defined $sock){ print "$name owns $sock\n"; }else{ print "No soup for $name\n"; }
    --perlplexer
      Thanks, but is there a way to do this without using a loop?

      "when a new client is created, we have to kill all the children..." --Sams Teach yourself Perl 5
Re: Accessing Multilevel Hash Values
by jehuni (Pilgrim) on Apr 24, 2002 at 13:40 UTC

    Assuming you mean that "socket" is actually a variable and not the hash key itself, this would give you a list of all matching sockets:

    my @sockets = grep { ref $connections{$_} eq 'HASH' && $connections{$_}{username} eq 'Bob' } keys %connections;

    -jehuni

    Update: Just to clarify, the ref $connections{$_} eq 'HASH' part is just in case you have things in %connections which are not hashrefs. On the other hand, if they're guaranteed to always be hashrefs, you could drop that check and just do:

    my @sockets = grep { $connections{$_}{username} eq 'Bob' } keys %conne +ctions;
Re: Accessing Multilevel Hash Values
by mce (Curate) on Apr 24, 2002 at 13:47 UTC
    Hi,
    This is mentioned in the perlfaq4 in the hashes part.
    The quick answer is: you always have to iterate.
    Please not that the username=>"Bob" part is a value of the primary hash.
    Your hash looks like this:
    %connections=( socket => { username => "Bob" } );
    Where the value is therefore a reference to another hash.
    So, your question is: how can I find the key when the value of a value is "Bob" and it's key is "username".
    I hope this helps
    ---------------------------
    Dr. Mark Ceulemans
    Senior Consultant
    IT Masters, Belgium
Re: Accessing Multilevel Hash Values
by Putzfrau (Beadle) on Apr 24, 2002 at 15:58 UTC
    Thank you all for your suggestions and solutions
    "when a new client is created, we have to kill all the children..." --Sams Teach yourself Perl 5