Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl hash when both the keys and the values are array references

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.

like image 1000
wchlm Avatar asked Oct 26 '11 05:10

wchlm


People also ask

Can a Perl hash value be an array?

The normal hash operations (insertion, deletion, iteration, and testing for existence) can now be written in terms of array operations like push , splice , and foreach . Once you have a key with many values, here's how to use them: @values = @{ $hash{"a key"} };

How do I create a hash from two arrays in Perl?

You can do it in a single assignment: my %hash; @hash{@array1} = @array2; It's a common idiom.

How do I pass an array to a hash in Perl?

use strict; use Data::Dumper; my @array= qw(foo 42 bar); my %hash; @{ $hash{key} } = @array; $hash{key} = [ @array ]; #same as above line print Dumper(\%hash,$hash{key}[1]);

How do you store an array in hash?

To assign that array to a hash element, you'd use either $b{"x"} = [@a] or $b{"x"} = \@a , depending on what you're trying to do. [@a] makes a new arrayref containing a copy of the current contents of @a . If the contents of @a change after that, it has no effect on $b{x} .


2 Answers

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
like image 95
socket puppet Avatar answered Nov 13 '22 08:11

socket puppet


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];
like image 29
Michael Carman Avatar answered Nov 13 '22 09:11

Michael Carman