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

Dear Monks,

the question is simple: I need a N:1 hash - several keys point to 1 value. I've of course searched for similar questions in the monastery and have found exactly what I'm searching for: japhy asked some 2 years ago in this node exactly for that.

Even better, merlyn answered with some code that has enlighted japhy, but - unfortunatedly - I'm as puzzled as before.

Probably it's because I still don't have enough experience with map and anonymous arrays, so I wasn't able to form merlyns code into something executable.

Any help on this would be greatly apreciated.

Bye
 PetaMem

Replies are listed 'Best First'.
Re: multiple keys in hash
by shotgunefx (Parson) on Jul 24, 2002 at 09:03 UTC
    It depends on what you are trying to do. If you just want to initilize some keys to the same values, that's one thing. If you want them to be aliases, where deleting one deletes all or modifying one, modifies all then that's another and probably best accomplished with tie.

    I belive I have a snippet somewhere here that does the latter. I'll try and scrounge around for it and post it when i find it.
    update
    Here it is. May I ask what you are trying to do? I did this for combining apps that used a tied config hash so I wouldn't have to "touch" any of them.
    update Noticed bug in DELETE. Fixed.
    package Tie::Hash::KeyAlias; use Carp; sub TIEHASH { my $class = shift; my $self = {}; $self->{aliases} = {} ; $self->{keys} = {@_}; $self->{keystore} = []; $self->{keystoreindex} = 0; bless $self, $class; } sub STORE { my ($self,$key,$value) = @_; if (exists $self->{aliases}{$key} ){ my $realkey = $self->{aliases}{$key}; $self->{keys}{$realkey} = $value; }else{ $self->{keys}{$key} = $value; } } sub FETCH { my ($self,$key) = @_; if (exists $self->{aliases}{$key} ){ my $realkey = $self->{aliases}{$key}; $self->{keys}{$realkey} ; }else{ $self->{keys}{$key}; } } sub DELETE { my ($self,$key) = @_; if (exists $self->{aliases}{$key} ){ my $realkey = $self->{aliases}{$key}; foreach my $k (keys %{$self->{aliases}}){ delete $self->{aliases}{$k} if $self->{aliases}{$k} eq $re +alkey; } delete $self->{keys}{$realkey} ; }else{ foreach my $k (keys %{$self->{aliases}}){ delete $self->{aliases}{$k} if $self->{aliases}{$k} eq $ke +y; } } delete $self->{keys}{$key}; } sub EXISTS { my ($self,$key) = @_; if (exists $self->{aliases}{$key} ){ my $realkey = $self->{aliases}{$key}; exists $self->{keys}{$realkey} ; }else{ exists $self->{keys}{$key}; } } sub DEFINED { my ($self,$key) = @_; if (exists $self->{aliases}{$key} ){ my $realkey = $self->{aliases}{$key}; defined $self->{keys}{$realkey} ; }else{ defined $self->{keys}{$key}; } } sub CLEAR { my $self = shift; $self = {}; } sub FIRSTKEY { my $self = shift; $self->{keystore} = [ keys %{$self->{keys}}, keys %{$self->{aliase +s}} ]; return shift @{$self->{keystore}}; } sub NEXTKEY { my $self = shift; return shift @{$self->{keystore}}; } sub alias { my $self = shift; my %aliases = (@_); foreach my $k (keys %aliases){ if (exists $self->{keys}{ $aliases{$k} } ){ $self->{aliases}{$k} = $aliases{$k}; }elsif(exists $self->{aliases}{ $aliases{$k} } ){ my $realkey = $self->{aliases}{ $aliases{$k} }; $self->{aliases}{$k} = $realkey; }else{ croak "Can't ALIAS to a non-existant key! $k => $aliases{$ +k}" ; } } } # EXAMPLE USAGE package main; use Data::Dumper; my %hash; tie %hash, 'Tie::Hash::KeyAlias'; $hash{key1} = '10'; $hash{anotherkey} = 55; tied(%hash)->alias( key2=>'key1', key3=>'key2'); print Dumper(\%hash); $hash{key3} ++; # Modify key1,key2,key3 print Dumper(\%hash); delete $hash{key2}; # delete key1,key2,key3 print Dumper(\%hash); untie %hash;


    -Lee

    "To be civilized is to deny one's nature."
Re: multiple keys in hash
by Abigail-II (Bishop) on Jul 24, 2002 at 09:40 UTC
    Probably easiest is not to store the values directly, but store references to the values. Keys that point to the same value store references to said value.

    You could even hide the extra layer behind a tie.

    Abigail

Re: multiple keys in hash
by Tomte (Priest) on Jul 24, 2002 at 09:51 UTC
    I had no problem to get something executable:
    #!/usr/bin/perl use strict; use Data::Dumper; my %hash = map { my $item = pop @$_; map { $_, $item } @$_ } [qw(HELP ?) => sub { print "help\n"; }], [qw(QUIT EXIT LEAVE) => sub { "exit"; }]; &{%hash->{HELP}}(); &{%hash->{'?'}}(); print Dumper(%hash); 1;

    yields

    help help $VAR1 = '?'; $VAR2 = sub { "DUMMY" }; $VAR3 = 'HELP'; $VAR4 = $VAR2; $VAR5 = 'EXIT'; $VAR6 = sub { "DUMMY" }; $VAR7 = 'QUIT'; $VAR8 = $VAR6; $VAR9 = 'LEAVE'; $VAR10 = $VAR6;

    The [qw xxx],[qw xxx] are the list on which the first (leftmost) map operates.
    For each [qw(X Y), anon_sub] the block of the leftmost map is executed and the result appended to the resulting hash.
    In this block the last element is fetched in $item (my $item = pop @$_;) and then for each remaing element, which is the key, used as value in the resulting hash
    (map { $_, $item } @$_)

    HTH,
    Tomte