Hash

Associative arrays are commonly known as hash in the perl community. If you don't know what I'm talking about in a case nor the other, think to them as unsorted collection of data pairs.

A pair has a first value, known as key (or hash key), that should be unique in the collection; and a second value, that has no special name (it is just called value) and no special constrain either.

We have seen that a perl scalar is identified by a $, an array by @, an hash has a % as a first character in its name.

There is a strong relation between array and hash. So strong, that it is easy create an hash from an array. Given this array:

my @months = ( "Jan", 31, "Feb", 28, "Mar", 31, "Apr", 30, "May", 31, "Jun", 30,
"Jul", 31, "Aug", 31, "Sep", 30, "Oct", 31, "Nov", 30, "Dec", 31
);
print "Months array: @months\n";

We create an hash from it simply by assignment:
my %months = @months;
But we should not expect that an hash would keep the elements in a specific order so, if we assign our hash to another array:

my @monthsA = %months;
print "Months again: @monthsA\n";

We have no guarantee that the elements in monthA would be in the same order that the ones in the month array.

We don't need to create an array as intermediate passage to an hash creation, we could directly initialize it as we would initialize an array:

my %monthsB = (
"Jan", 31,
"Feb", 28,
"Mar", 31,
"Apr", 30,
"May", 31,
"Jun", 30,
"Jul", 31,
"Aug", 31,
"Sep", 30,
"Oct", 31,
"Nov", 30,
"Dec", 31
);

There is an alternative notation, that uses the comma-arrow operator "=>" to make a bit clearer the statement, showing more explicitely the relation between key and value in the hash:

my %monthsC = ( Jan => 31, Feb => 28, Mar => 31, Apr => 30, May => 31, Jun => 30,
Jul => 31, Aug => 31, Sep => 30, Oct => 31, Nov => 30, Dec => 31
);

Since it is so common to have a string as key in an hash, the comma-arrow operator is designed to implicitly quote the characters on its left, converting them in a string.

Once we have an hash, we can get a value associated to a key using a notation close to the one for array:
print "Days in October: $months{Oct}\n";
The difference is that we have to use curly brackets and not square ones.

Instead of using a literal value (without qoutes), we can use a scalar:

my $month= "May";
print "Days in $month: $months{$month}\n";

Let's start again from an empty hash:
my %where;
We can add an element using the the same curly bracket notation we have used for reading an element:

$where{Eva} = "Turin";
print "Eva lives in $where{Eva}\n";

We should pay attention to the fact that key in an hash are unique so, if we use a key that is already in the hash, we don't add a new element, but change the value associated to the existing one:

$where{Eva} = "Berlin";
print "Eva lives in $where{Eva}\n";

Using an hash variable in a scalar context, gives us the number of element currently in the hash (and the total room currently available, more on this in a future post, I guess):
print %where."\n";
Notice that I didn't put the hash variable name in the string, because - try it yourself - that is not a smart move. Perl doesn't recognize it as an hash and print it as a literal string.

To get rid of an element, we use the delete operator:

delete $where{Eva};
print %where."\n";

After using it, we see that the number of element in the hash decreases. If we want to check directly if there is a specified key in an hash, we use the exists() function:

if(!exists $where{Eva}) {
print "No Eva here\n";
}


If we want

There are a couple of useful functions that help us working with hashes. With keys() we get an array containing all the keys in the passed hash, and values() does the same with the values, as someone would have correctly guessed:

my @kMonths = keys(%months);
print "@kMonths\n";

my @vMonths = values(%months);
print "@vMonths\n";

Actually, there are not many cases in which values() comes to help. On the other side, keys() could be very useful - here we see it at work for looping on all the elements of an hash:

for (keys %months) {
print "$_ has $months{$_} days\n";
}

Just do not expect to have the months printed in a specific order.

Chapter 3 of Beginning Perl by Simon Cozens is about arrays and associative arrays (hashes).

No comments:

Post a Comment