This chapter will introduce the third major Perl abstract data type, associative arrays. Also known as hashes, associative arrays provide native language support for one of the most useful data structures that programmers implement--the hash table.
Associative arrays, also frequently called hashes, are the third major data type in Perl after scalars and arrays. Hashes are named as such because they work very similarly to a common data structure that programmers use in other languages--hash tables. However, hashes in Perl are actually a direct language supported data type.
We have seen that each of the different native data types in Perl has a
special character that identify that the variable is of that type.
Hashes always start with a %
.
Accessing a hash works very similar to accessing arrays. However, hashes are
not subscripted by numbers. They can be subscripted by an arbitrary scalar
value. You simply use the {}
to subscript the value instead of
[]
as you did with arrays. Here is an example:
use strict; my %table; $table{'schmoe'} = 'joe'; $table{7.5} = 2.6;
In this example, our hash, called, %table
, has two entries. The key
'schmoe'
is associated with the value 'joe'
, and the key
7.5
is associated with the value 2.6
.
Just like with array elements, hash elements can be used anywhere a scalar variable is permitted. Thus, given a @hash{%table} built with the code above, we can do the following:
print "$table{'schmoe'}\n"; # outputs "joe\n" --$table{7.5}; # $table{7.5} now contains 1.6
Another interesting fact is that all hash variables can be evaluated in
the list context. When done, this gives a list whose odd elements are
the keys of the hash, and whose even elements are the corresponding
values. Thus, assuming we have the same %table
from above, we
can execute:
my @tableListed = %table; # @tableListed is qw/schmoe joe 7.5 1.6/
If you happen to evaluate a hash in scalar context, it will give you
undef
if no entries have yet been defined, and will evaluate to true
otherwise. However, evaluation of hashes in scalar context is not
recommended. To test if a hash is defined, use defined(%hash)
.
"Hash literals" per se do not exist. However, remember that when we evaluate a hash in the list context, we get the pairs of the hash unfolded into the list. We can exploit this to do hash literals. We simply write out the list pairs that we want placed into the hash. For example:
use strict; my %table = qw/schmoe joe 7.5 1.6/;
would give us the same hash we had in the previous example.
You should realize that any function you already know that works on arrays will also work on hashes, since you can always evaluate a hash in the list context and get the pair list. However, there are a variety of functions that are specifically designed and optimized for use with hashes.
When we evaluate a hash in a list context, Perl gives us the paired list
that can be very useful. However, sometimes we may only want to look at
the list of keys, or the list of values. Perl provides two optimized
functions for doing this: keys
and values
.
use strict; my %table = qw/schmoe joe smith john simpson bart/; my @lastNames = keys %table; # @lastNames is: qw/schmoe smith simpson/ my @firstNames = values %table; # @firstNames is: qw/joe john bart/
The each
function is one that you will find particularly useful when
you need to go through each element in the hash. The each
function
returns each key-value pair from the hash one by one as a list of two
elements. You can use this function to run a while
across the hash:
use strict; my %table = qw/schmoe joe smith john simpson bart/; my($key, $value); # @cc{Declare two variables at once} while ( ($key, $value) = each(%table) ) { # @cc{Do some processing on @scalar{$key} and @scalar{$value}} }
This while
terminates because each
returns undef
when all the pairs have been exhausted. However, be careful. Any
change in the hash made will "reset" the each
function for that
hash.
So, if you need to loop and change values in the hash, use the following
foreach
across the keys:
use strict; my %table = qw/schmoe joe smith john simpson bart/; foreach my $key (keys %table) { # Do some processing on $key and $table{$key} }
It turns out you can slice hashes just like you were able to slice arrays. This can be useful if you need to extract a certain set of values out of a hash into a list.
use strict; my %table = qw/schmoe joe smith john simpson bart/; my @friends = @table{'schmoe', 'smith'}; # @friends has qw/joe john/
Note the use of the @
in front of the hash name. This shows that we
are indeed producing a normal list, and you can use this construct in any
list context you would like.
We have now discussed all the different ways you can use variables in list and scalar context. At this point, it might be helpful to review all the ways we have used variables in different contexts. The table that follows identifies many of the ways variables are used in Perl.
Expression | Context | Variable | Evaluates to |
$scalar | scalar | $scalar , a scalar |
the value held in $scalar
|
@array | list | @array , an array |
the list of values (in order) held in @array
|
@array | scalar | @array , an array |
the total number of elements in @array (same as
$#array + 1 )
|
$array[$x] | scalar | @array , an array |
the ($x+1) th element of @array
|
$#array | scalar | @array , an array |
the subscript of the last element in @array (same as
@array -1 )
|
@array[$x, $y] | list | @array , an array |
a slice, listing two elements from @array (same as
($array[$x], $array[$y]) )
|
"$scalar" | scalar (interpolated) | $scalar , a scalar |
a string containing the contents of $scalar
|
"@array" | scalar (interpolated) | @array , an array |
a string containing the elements of @array , separated by
spaces
|
%hash | list | %hash , a hash |
a list of alternating keys and values from %hash
|
$hash{$x} | scalar | %hash , a hash |
the element from %hash with the key of $x
|
@hash{$x, $y} | list | %hash , a hash |
a slice, listing two elements from %hash (same as
($hash{$x}, $hash{$y})
|
Go to the first, previous, next, last section, table of contents.