my $h = TwoWayHash->new(100); # 100 is the "size", ignore for now $h->insert("mam", "dad"); print $h->retrieveOneWay("L2R", "mam") # Left 2 Right # dad print $h->retrieveOneWay("R2L", "dad") # Right 2 Left # mam #### tie %r2l, $twowayhash, "R2L"; # right to left tie %l2r, $twowayhash, "L2R"; # left to right #### use strict; use warnings; package TwoWayHash; sub new { my $pkg = shift; my $size = shift; my $self = bless {Size => $size}, $pkg; # preextend the buckets $self->{R2L} = []; $#{$self->{R2L}} = $size - 1; $self->{L2R} = []; $#{$self->{L2R}} = $size - 1; return $self; } sub insert { my $self = shift; my ($v1, $v2) = @_; $self->insertOneWay("L2R", \$v1, \$v2); $self->insertOneWay("R2L", \$v2, \$v1); } sub insertOneWay { my $self = shift; my $which = shift; my $key = shift; # these are refs to the strings my $value = shift; my $h = _hashit($key) % $self->{Size}; # turn the key into something much smaller and hopefully unique my $buckets = $self->{$which}; # find the already existing bucket or create a # new one then put the key/value into the bucket my $bucket = $buckets->[$h] ||= []; push(@$bucket, $key, $value); } sub _hashit { # a terrible hash function! It just takes the first 2 characters of the string # and turns them into a number between 0 and 65535 # You'll need something better for real life my $rstr = shift; return unpack("S", substr($$rstr, 0, 2)); } sub retrieveOneWay { my $self = shift; my $which = shift; my $key = shift; # not a ref this time my $h = _hashit(\$key) % $self->{Size}; my $buckets = $self->{$which}; if (defined(my $list = $buckets->[$h])) { # go through the list of pairs of key/values and see if any are the ones # we want my $i = 0; while ($i < $#$list) { if ($key eq ${$list->[$i]}) { return ${$list->[$i + 1]}; } $i += 2; } } # if we get here then we didn't find anything nice return undef; } 1; #### use strict; use warnings; use Test::More 'no_plan'; use Test::NoWarnings; # comment out if you don't have this installed use TwoWayHash; my $h = TwoWayHash->new(100); my @tests = ( ["abcd123", "efgh123"], ["wxyz456", "lmno456"], ["abcd456", "efgh456"], ); foreach my $test (@tests) { my ($v1, $v2) = @$test; $h->insert($v1, $v2); } use Data::Dumper; #print Dumper(\$h); foreach my $test (@tests) { my ($v1, $v2) = @$test; is($h->retrieveOneWay("L2R", $v1), $v2, "L2R retrieve '$v1'"); is($h->retrieveOneWay("L2R", $v2), undef, "L2R don't retrieve '$v2'"); is($h->retrieveOneWay("R2L", $v2), $v1, "R2L retrieve '$v2'"); is($h->retrieveOneWay("R2L", $v1), undef, "R2L don't retrieve '$v1'"); } is($h->retrieveOneWay("L2R", "abcd234"), undef, "L2R don't retrieve");