Wednesday, September 9, 2009

perl: hash of array, hash of hash

Answer: How do I make a hash of arrays?
contributed by chromatic

my %dramatis_personae = ( humans => [ 'hamnet', 'shakespeare', 'robyn', ], faeries => [ 'oberon', 'titania', 'puck', ], other => [ 'morpheus, lord of dreams' ], );
[download]

Access it like this:

foreach my $group (keys %dramatis_personae) { print "The members of $group are\n"; foreach (@{$dramatis_personae{$group}}) { print "\t$_\n"; } }
[download]

Answer: How do I make a hash of arrays?
contributed by Anonymous Monk

my @arrayOne = 1..10; my @arrayTwo = 20..30; my %HashOfArrays = ( one => \@arrayOne ); $HashOfArrays{two} = \@arrayTwo; $HashOfArrays{IpointToTheSameArrayAsOne} = \@arrayOne ; $HashOfArrays{IreferenceTheSameArrayAsOne} = \@arrayOne ; $HashOfArrays{MyValueIsThatOfOneAsWell} = \@arrayOne ;
[download]

## to create an array reference, just type \@array
## or [ @array ]
## [ @array ] does not equal \@array
## see perlref for more info

Answer: How do I make a hash of arrays?
contributed by Anonymous Monk

You can always...

push(@{$hash{$key}}, $insert_val);
[download]


...to load the arrays in the hash. That way you don't have to build the arrays, then dereference them into the hash.
Answer: How do I make a hash of arrays?
contributed by Doraemon

my $array = []; #create new anonymous array ref push (@$array, '11'); push (@$array, '12'); push (@$array, '13'); $hash{'first'} = $array; # add $array = []; #create a new anon-array push (@$array, '21'); push (@$array, '22'); push (@$array, '23'); $hash{'second'} = $array; # add print "Hash content\n"; foreach $k (keys %hash) { foreach (@{$hash{$k}}) { print " : $_"; } print "\n"; }
[download]

Please (register and) log in if you wish to add an answer

# Posts are HTML formatted. Put

tags around your paragraphs. Put tags around your code and data!
# Read Where should I post X? if you're not absolutely sure you're posting in the right place.
# Please read these before you post! —

* How do I compose an effective node title?
* How do I post a question effectively?
* Markup in the Monastery

# Posts may use any of the Perl Monks Approved HTML tags:

a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul

# Outside of code tags, you may need to use entities for some characters:
For: Use:
& &
< <
> >
[ [
] ]
# Link using PerlMonks shortcuts! What shortcuts can I use for linking?
# See Writeup Formatting Tips and other pages linked from there for more info.



====================================
Perl Hash Howto

This howto comes with no guaratees other than the fact that these code segments were copy/pasted from code that I wrote and ran successfully.

Initialize (clear, or empty) a hash.

Assigning an empty list is the fastest method.

Solution

my %hash = ();

Note

People have asked how to initialize a hash reference (aka hash ref). It's just like any scalar variable; you can use my alone, or you can assign a value.

my $hash_ref;
my $hash_ref = 0; # zero

Copy a hash.

Solution

my %hash_copy = %hash; # copy a hash

my $href_copy = $href; # copy a hash ref

Delete a single key/value pair.

The solution differs for a hash and a hash reference, but both cases can use the delete function.

Solution

Hash:

delete $hash{$key};

Hash reference:

delete $hash_ref->{$key};

Perform an action on each key/value pair in a hash.

The actions below print the key/value pairs.

Solution

Use each within a while loop. Note that each iterates over entries in an apparently random order, but that order is guaranteed to be the same for the functions keys and values.

while ( my ($key, $value) = each(%hash) ) {
print "$key => $value\n";
}

A hash reference would be only slightly different:

while ( my ($key, $value) = each(%$hash_ref) ) {
print "$key => $value\n";
}

Solution

Use keys with a for loop.

for my $key ( keys %hash ) {
my $value = $hash{$key};
print "$key => $value\n";
}

Example

my $file = $ARGV[0] || "-";

my %from = ();

open FILE, "< $file" or die "Can't open $file : $!";

while( ) {
if (/^From: (.*)/) { $from{$1}++ } # count recurrences of sender
}

close FILE;

for my $sender ( sort keys %from ) {
print "$sender: $from{$sender}\n";
}

Get the size of a hash.

Solution

print "size of hash: " . keys( %hash ) . ".\n";

Solution

my $i = 0;

$i += scalar keys %$hash_ref; # method 1: explicit scalar context
$i += keys %$hash_ref; # method 2: implicit scalar context

Use hash references.

Solution

sub foo
{
my $hash_ref;

$hash_ref->{ 'key1' } = 'value1';
$hash_ref->{ 'key2' } = 'value2';
$hash_ref->{ 'key3' } = 'value3';

return $hash_ref;
}

my $hash_ref = foo();

print "the keys... ", sort keys %$hash_ref, "...\n";

Function to build a hash of hashes; return a reference.

Solution

sub foo
{
my ( $login, $p, $uid, $gid, $gecos, $dir, $s );

my %HoH = ();

my $file = '/etc/passwd';
open( PASSWD, "< $file" ) or die "Can't open $file : $!";

while( ) {
( $login, $p, $uid, $gid, $gecos, $dir, $s ) = split( ':' );

$HoH{ $login }{ 'uid' } = $uid;
$HoH{ $login }{ 'gid' } = $gid;
$HoH{ $login }{ 'dir' } = $dir;
}

close PASSWD;

return \%HoH;
}

Access and print a reference to a hash of hashes.

Solution

my $rHoH = foo();

my( $uid, $gid, $dir );

for my $login ( keys %$rHoH ) {

$uid = $rHoH->{ $login }->{ 'uid' }; # method 1 most readable
$gid = ${ $rHoH->{ $login } }{ 'gid' }; # method 2
$dir = ${ ${ $rHoH }{ $login } }{ 'dir' }; # method 3 least readable

print "uid: $uid, gid: $gid, dir, $dir.\n";
}

Solution

my $rHoH = foo();

for my $k1 ( sort keys %$rHoH ) {
print "k1: $k1\n";
for my $k2 ( keys %{$rHoH->{ $k1 }} ) {
print "k2: $k2 $rHoH->{ $k1 }{ $k2 }\n";
}
}

Function to build a hash of hashes of hashes; return a reference.

Solution

sub foo
{
my %HoHoH = ();

while( ... ) {

if( /LOCATION:/ ) {

...

} elsif( /MODULE:/ ) {

$HoHoH{ $loc }{ $module_type }{ MODULE_NAME } = $module_name;

} elsif( $ARGS_ALLOWED ) {

$HoHoH{ $loc }{ $module_type }{ $arg_name } = $arg_value;

}

}

return \%HoHoH;
}

Access and print a reference to a hash of hashes of hashes.

Solution

my $rHoH = foo();

for my $k1 ( sort keys %$rHoHoH ) {
print "$k1\n";

for my $k2 ( sort keys %{$rHoHoH->{ $k1 }} ) {
print "\t$k2\n";

for my $k3 ( sort keys %{$rHoHoH->{ $k1 }->{ $k2 }} ) {
print "\t\t$k3 => $rHoHoH->{ $k1 }->{ $k2 }->{ $k3 }\n";
}
}
}

Print the keys and values of a hash, given a hash reference.

Solution

while( my ($k, $v) = each %$hash_ref ) {
print "key: $k, value: $v.\n";
}

Determine whether a hash value exists, is defined, or is true.

Solution

print "Value EXISTS, but may be undefined.\n" if exists $hash{ $key };
print "Value is DEFINED, but may be false.\n" if defined $hash{ $key };
print "Value is TRUE at hash key $key.\n" if $hash{ $key };

Example

Let's say we execute an sql query where some of the resulting values may be NULL. Before attempting to use any of the values we should first check whether they are defined, as in the following code. Note that the subroutine sql_fetch_hashref() takes care of connecting to the database, preparing the statement, executing it, and returning the resulting row as a hash reference using DBI's fetchrow_hashref() method.

my $answers = 'a,b,c,d,e';

my $sql = "select max_time, $answers from questions " .
'where question_number=?';
my $hash_ref = sql_fetch_hashref( $sql, $q );

my @answers = split ',', $answers;

my $max_time = $hash_ref->{max_time} || '60';

my $hash_ref_ans;
for my $letter ( @answers ) {
$hash_ref_ans->{ $letter } = $hash_ref->{ $letter }
if defined $hash_ref->{ $letter };
}

The for loop made a new hash of only defined key/value pairs.

How to make hash of array

$Hash{$key} = \@Array -> @Array = @{$Hash{$key}}

No comments:

Post a Comment