5

I have a problem where pairs of numbers map to other pairs of numbers. For instance, (1,2)->(12,97). Some pairs may map to multiple other pairs, so what I really need is the ability to map a pair into a list of lists, like (1,2)->((12,97),(4,1)). At the end of the day I want to process each of the values (i.e., each list of lists) separately.

In Python, I could do this by simply saying:

key = ( x, y )
val = [ a, b ]
if (x,y) not in my_dict:
    my_dict[ (x,y) ] = []
my_dict[ (x,y) ].append( [a,b] )

However, in Perl, I have to use refs for the keys and values. So I can certainly say:

$keyref = [ x1, y1 ]
$valref = [ a, b ]
%my_hash = { $keyref => $valref }

But what happens when another pair (x2,y2) comes along? Even if x2==x1 and y2==y1, $keyref=[x2,y2] will differ from the previous keyref generated, so I do not see a way to do the lookup. Of course, I could compare (x2,y2) with each dereferenced hash key, but after all, God gave us hash tables precisely to avoid the need to do so.

Is there a Perl solution?

Thanks,

-W.

1
  • You can't use a reference as a key. ( at least no without using a tied hash ) Commented Oct 26, 2011 at 23:53

3 Answers 3

10

In Perl, all hash keys are strings, or are "stringified" before lookup. Using an array reference as a key is usually the wrong approach.

What about using a "two-dimensional" hash?

$hash{$x1}{$y1} = [ $a, $b ];
# or
%hash = ( $x1 => { $y1 => [ $a, $b ] } );


($x2,$y2)=($x1,$y1);
print @{$hash{$x2}{$y2}};   # will print $a and $b
Sign up to request clarification or add additional context in comments.

Comments

2

Like most things in Perl, TMTOWTDI.

Option 1: Use multidimensional array emulation

$hash{$x,$y} = [$a, $b];

See also the documentation for the built-in variable $;.

Option 2: Use the Hash::MultiKey module

tie %hash, 'Hash::MultiKey';
$hash{[$x, $y]} = [$a, $b];

Option 3: Use a HoH (hash of hashes) instead

$hash{$x}{$y} = [$a, $b];

1 Comment

I ended up using Socket Puppet's solution (in the form of your Option 3). FYI, here is a little Perl script that carries out all the operations I need to do in my app. Printed lines 2:,3: and 4:,5: just use different syntax to do the same things, and 0: and 1: were just intended as sanity checks along the way. The only thing this adds to these examples is the use of an array of arrays as the value that goes along with the keys.
0

I ended up using Socket Puppet's solution (in the form of Michael Carmen's Option 3). FYI, here is a little Perl script that carries out all the operations I need in my app.

Printed lines 2:,3: and 4:,5: just use different syntax to do the same thing, and lines 0: and 1: were just intended as sanity checks along the way.

What this this adds to the suggested solution is the use of an array of arrays as the value that goes along with a key.

@k1 = ( 12, 13 );
$aref = [ 11, 22 ];
$bref = [ 33, 44 ];
%h = {};
if( not exists $h{$k1[0]}{$k1[1]} ) {
    print "initializing\n";
    $h{$k1[0]}{$k1[1]} = [];
}
push @{$h{$k1[0]}{$k1[1]}}, $aref;
push @{$h{$k1[0]}{$k1[1]}}, $bref;
print "0: ", join ':', @{$h{$k1[0]}{$k1[1]}}, "\n";
print "1: ", join ':', ${$h{$k1[0]}{$k1[1]}}[0], "\n";
print "2: ", join ':', @{${$h{$k1[0]}{$k1[1]}}[0]}, "\n";
print "3: ", join ':', @{${$h{$k1[0]}{$k1[1]}}[1]}, "\n";
print "4: ", join ':', @{$h{$k1[0]}{$k1[1]}->[0]}, "\n";
print "5: ", join ':', @{$h{$k1[0]}{$k1[1]}->[1]}, "\n";

P.S. I would have added this as a comment but it was too long, and I thought it made sense to include a worked example.

1 Comment

Congrats on the solution. When you are able, please make sure to mark your answer as 'accepted' so that others might learn from your success. Cheers~

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.