Login

Hash Functions

In this second part of a two-part series on hashes in Perl, you’ll learn about hash functions and hashes in different contexts. This article is excerpted from chapter five of the book Beginning Perl, written by James Lee (Apress; ISBN: 159059391X).

Hash in List Context

When we discussed lists and arrays, we spent a lot of time talking about the difference between list and scalar context. Let’s look at what happens when we evaluate a hash in list context. This is demonstrated with the following program:

prints the string “scalar context: 3/8”. Therefore, this hash in scalar context is “3/8” which means that we are using three buckets, or memory locations, out of eight buckets allocated.

This string is not so interesting unless we notice that the string “3/8” is a true value in Perl. Also, if our hash was empty, its value in scalar context would be the empty string, "". So a hash in scalar context is normally treated as a true/false value—true if there is anything in it, false if empty:

Since hashes in list context are apparently random collections of key/value pairs, we can’t really use foreach loops on them directly. If we did, we would get both keys and values with no indication as to which was which. To help us, Perl provides three functions for iterating over hashes:
keys()
,
values()
, andeach()
.

Also, Perl provides functions to remove elements (
delete()
, already seen previously), and to check to see if a key exists in the hash (
exists()
).

The keys() Function

First, there is keys(%hash). This gives us a list of the keys (all of the scalars on the left-hand side). This is usually what we want when we wish to visit each hash entry in turn as shown in this example:

You may find that the output appears in a different order on your machine.1 Don’t worry. As mentioned before, hashes are unordered, and there’s no guarantee that the keys will come out in the same order each time. It really depends on the particular version of Perl that you are using.

Let’s look at the part of the program that does all the work:

foreach (keys %where) { print "$_ lives in $where{$_}n";
}

keys()
is a function which, like
sort()
and
reverse()
, returns a list. The list in this case isqw(Lucy Samantha Gary Ian)
, and the
foreach
loop visited each of those values in turn. As
$_
was set to each one, we could print the name and look up that entry in the hash.

The values() Function

The counterpart to keys() is
values()
, which returns a list of all of the values in the hash. This is somewhat less useful, since you can always find the value if you have the key, but you cannot easily find the key if you have the value. It’s almost always advantageous to use
keys()
instead.

The next hash function is each(). It returns each hash entry as a key/value pair. Normally, the values returned are copied into an assignable list like this:

each() . It returns hash entry as a key/value pair. Normally, the values returned are copied into an assignable list like this:
The next hash function is each(). It returns hash entry as a key/value pair. Normally, the values returned are copied into an assignable list like this:

We have already seen the delete()function. It removes a key/value pair from a hash. This statement from
badhash.pl
removes the pair Lucy/Exeter from%where
:

delete $where{Lucy};

Since we are on the subject, we should mention that the
delete()
function also deletes array elements. The following code would remove element 3 from the array
@array
. Note that the element returns to an uninitialized state:

delete $array[3];

The exists() Function

The last function we will look at is the exists() function. It returns true if the key exists in the hash, false if not. Here is an example:

exists() function. It returns true if the key exists in the hash, false if not. Here is an example:
The last function we will look at is the exists() function. It returns true if the key exists in the hash, false if not. Here is an example:

print "Gary exists in the hash!n" if exists $where{Gary};
print "Larry exists in the hash!n" if exists $where{Larry};

Running this program results in the following:

$ perl exists.plGary exists in the hash!
$

Note exists()
returns 1 when true, an empty string when false.

The
exists()
function also works for array elements. This code checks to see if element 3 exists in
@array
:

if (exists $array[3]) { print "element 3 exists!n";
}

{mospagebreak title=Hash Examples}

Hashes are very useful variables and there are many uses for them. Here are a few examples of using hashes to solve common problems.

Creating Readable Variables

The most basic use of a hash is to be able to index into a variable to obtain information using a readable string which is far more user-friendly than using a numeric index as we would with an array. For instance, this program shows that we can create a record of strings representing RGB colors that one might find in an HTML page:

Notice how the information in the hash is laid out in such a way that it is readable by human beings. It is easy to see that the RGB string for “red” is “#FF0000” and indexing into the hash is the human-friendly
$colors{red}
.

Executing this code produces the following:

$ perl colors.plRed is: #FF0000
Blue is: #0000FF
Purple is: #520063
$

“Reversing” Information

Recall the hash we created earlier in this chapter that was a collection of people and where they lived:

If you need to turn this hash around to look up people by where they live, you can use a hash in list context that produces a list of key/value pairs, reverse the list with the
reverse()
function, and then assign it to a new hash.

%who = reverse %where;

Be careful though—if you have two values that are the same, then converting them to keys means that one will be lost. Remember that keys must be unique.

we see that
@names
is a collection of 12 names. Upon close inspection, we see that “John” occurs four times, “Sue” occurs once, and so on.

We can use a hash to keep a count of the number of times a name occurs in
@names
by creating a hash that will have the names as its keys, and the number of occurrences of the name as the value associated with the key. For instance, when all the names in
@names
are processed, we will end up with a hash that resembles

This code implements the logic “For each name in the array, if the name already exists in the hash, then increment the value by 1 (incrementing the count); else if it does not exist in the hash, then add the name to the hash with the initial value of 1.” After all the names are processed, then the hash will contain all the names and the number of times that each name is present in
@names
.

For minimalists, the
if
statement can be shortened because this logic:

if (exists $count{$_}) {
$count{$_}++;
} else {
$count{$_} = 1;
}

is built into the statement

$count{$_}++;

Therefore, our
foreach
loop could be changed to

foreach (@names) {
$count{$_}++;
}

or more simply

$count{$_}++ foreach @names;

Summary

Hashes are unordered structures made up of pairs, each pair consisting of a key and a value, and given the key we can look up the value. Generally,$hash{$key} = $value. We can loop over all the elements of a hash by processing the keys using a
foreach
loop to go through the keys.

Hashes are very useful variables that allow us to create data that is human-readable, reversible, and often used for counting things.

Exercises

Create this hash variable:

scalar => ‘dollar sign’,
array => ‘at sign’,
hash => ‘percent sign’

Process it with a
foreach
loop that prints the key/value pairs so that the keys are printed in sorted order:

array: at sign
hash: percent sign
scalar: dollar sign

Store your important phone numbers in a hash. Write a program to look up numbers by the person’s name.

Turn the joke machine program in Chapter 4 from two arrays into one hash. While doing so, write some better lightbulb jokes.