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

Hi, I want to have a one to one relationship.

e.g. "ger" <--> "german"
e.g. "ara" <--> "arabic"
e.g. "eng" <--> "english"

I always only know the left (e.g. "ger") or right value (e.g. "german") and I have to get the other value.

I tried to solve this problem with a hash. But then I have the problem that I do not get the key when I have the value. Here an example.

#!/usr/bin/perl use strict; use warnings; my %languages = ( "ger" => "german", "ara" => "arabic", "eng" => "english" ); # with the key it is easy to get to the value foreach my $key (keys %languages ) { print "$key <--> $languages{$key}" . "\n"; } # but how do I get key if I only have the value # e.g. I know "german", but how do I get "ger"? foreach my $value (values %languages ) { print "$value <--> ???" . "\n"; }

How would you solve this problem?

Thank you very much Dirk

Replies are listed 'Best First'.
Re: One to one relationship
by Anonymous Monk on Oct 30, 2009 at 10:21 UTC
    my %reverse = reverse %languages; print $languages{$key} || $reverse{$key};
Re: One to one relationship
by toolic (Bishop) on Oct 30, 2009 at 13:35 UTC
Re: One to one relationship
by herveus (Prior) on Oct 30, 2009 at 11:32 UTC
    Howdy!

    As you have noted, the hash gives you the mapping in one direction only. To get the other way, you need another hash. Anonymous Monk's offering above is a fine way to get there.

    yours,
    Michael
Re: One to one relationship
by ikegami (Patriarch) on Oct 30, 2009 at 15:15 UTC
    # Get the value for each key for my $key (keys %languages ) { print "$key --> $languages{$key}\n"; } # Get the keys for each value for my $value ( values %languages ) { for my $key ( keys %languages ) { print "$key --> $value\n" if $languages{$key} eq $value; } }

    You need to visit all the keys to do a reverse matching. In general, you also have to worry about the case where keys map to the same value.

    Since you have a one-to-one mapping, you can use a pair of hashes to do efficient lookups in both directions. The downside is that you must keep the two hashes in sync.

Re: One to one relationship
by biohisham (Priest) on Oct 30, 2009 at 15:07 UTC
    The replies provided were fantastic.. I am not really sure if a bidirectional hash with key-value value-key combinations can also be considered and equally efficient in case you have a large amount of relations. Dear Monks please be free to criticize this, I aspire to learn by interaction.

    This code here can let you treat all the right and left values as keys and as values of each other, then you may want to use the hash as a search dictionary:

    #!/usr/local/bin/perl #title "One to one relationship"; use strict; use warnings; use diagnostics; my %hash; while(<DATA>){ next unless /"(\w+)".*"(\w+)"/gs; $hash{$1}=$2; $hash{$2}=$1; } use Data::Dumper; print Data::Dumper->Dump ([\%hash]); __DATA__ "ger" <--> "german" "ara" <--> "arabic" "eng" <--> "english"

    here's the output:

    $VAR1 = { 'arabic' => 'ara', 'ara' => 'arabic', 'ger' => 'german', 'german' => 'ger', 'english' => 'eng', 'eng' => 'english' };


    Excellence is an Endeavor of Persistence. Chance Favors a Prepared Mind.

      This strategy is exactly what I was thinking, too. It saves having to deal with two different hashes (which several of the other responders recommended and certainly would work as they offer).

      As ikegami notes, however, either this strategy (where only a single hash is used) or the two-hash strategy, only works if it is a true one-to-one mapping of keys to values. If that requirement is met, then it seems to me that neither strategy will work. In that case, I think the op has a whole different challenge.

      ack Albuquerque, NM
Re: One to one relationship
by wol (Hermit) on Nov 02, 2009 at 17:29 UTC
    If you want to ensure that your relationship is one-to-one, then you could check at run-time like this:
    my %reverse = reverse %hash; die "Useful message" unless scalar keys %reverse == scalar keys %hash;

    --
    use JAPH;
    print JAPH::asString();