Perl using hash variables
In Perl, a hash lets you create a one-to-one association between a variable, called the key, and a value. We’ll show you the basics of Perl hashes and some useful tricks.
One of the most useful constructs in Perl is the humble array, which lets you store more than one value in a single variable. This is very useful if you have a set of related values—for example, a shopping list—and you need to group them into a collection, yet be able to access them individually.
A variant of the regular array, which is indexed by number, is the hash or associative array, which is indexed by key. A hash is a Perl construct that allows a programmer to create one-to-one associations between a variable, or “key,” and its value. Elements of a hash can be accessed only via their keys, and keys within a hash must be unique.
Get ready, because we’re about to give you a crash course in how Perl hashes work. And we’ll show you some examples of where you can use them.
Hash basics
Creating a Perl hash is very similar to defining an array: You create a hash variable and (optionally) assign some keys and values to it:
# define hash
%account = (‘username’ => ‘jimmyboy’, ‘password’ => ‘scar3me’);
Notice the % symbol preceding the variable name, and contrast it to the @ sign preceding an array. Notice also the => symbol, which is used to connect a key to its associated value.
Hash elements consist of a key-value pair. Each key in a hash is unique and serves as a unique identifier for the corresponding value. The value can be retrieved only if you know the corresponding key. Therefore, in the example above, you would retrieve the value jimmyboy with the following notation:
# retrieve value of hash element
print $account{‘username’};
To add new elements to a hash, define a new key-value pair, and Perl will automatically add it to the hash variable:
# add an element to a hash
$account{‘active’} = 1;
# the hash now contains
%account = (‘username’ => ‘jimmyboy’, ‘password’ => ‘scar3me’, ‘active’ => 1);
Note that unlike arrays, Perl hashes are not arranged in any specific numerical order or in the order in which the keys are added. Rather, Perl uses its own sorting algorithms to arrange the elements in an optimal manner. For this reason, you must always access hash values by key rather than position.
To remove an element from a hash, use the delete() function as shown below. Don’t even think about using the infamous—and flawed—technique of assigning an empty value to the key. That just leaves the key in the array with a null value. It doesn’t actually remove the key, which is why you need to use delete() instead.
# delete the named key from the hash
delete($account{‘password’});
Hashes and regular arrays mix well with each other, so it’s even possible to have a hash key pointing to an array (or vice versa), as in this example:
# hash keys pointing to an array
%combo = (‘colors’ => [‘red’, ‘green’, ‘blue’], ‘vowels’ => [‘a’, ‘e’, ‘i’, ‘o’, ‘u’]);
Processing hash elements
Perl offers the keys() and values() functions to obtain lists of all the keys and values present in a hash. These functions come in handy when you need to process all the elements in a hash using a foreach() loop. The following example iterates over a hash and writes the elements to a file as comma-separated key-value pairs.
# set up hash
%capitals = (‘china’ => ‘beijing’, ‘england’ => ‘london’, ‘france’ => ‘paris’, ‘norway’ => ‘oslo’, ‘italy’ => ‘rome’);
# open file
open (FILE, “>data.txt”);
# process hash elements
# write to file in csv format
foreach $k (keys (%capitals))
{
print FILE $k, “,”, $capitals{$k}, “\n”;
}
# close file
close(FILE);
Note that the keys() function returns an array. By iterating over this array in a foreach() loop, it becomes possible to process each and every element in the hash.
Another option is to use the each() function, which iteratively moves through a hash creating a two-item array at each stage for the current key and value. The each() function is thus well suited to a while() loop, as illustrated in this rewrite of the previous example:
# set up hash
%capitals = (‘china’ => ‘beijing’, ‘england’ => ‘london’, ‘france’ => ‘paris’, ‘norway’ => ‘oslo’, ‘italy’ => ‘rome’);
# open file
open (FILE, “>data.txt”);
# process hash elements
# write to file in csv format
while ( ($country, $capital) = each (%capitals))
{
print FILE $country, “,”, $capital, “\n”;
}
# close file
close(FILE);
Quick tip: If all you really want to do is check if a particular value exists in a hash, don’t waste time by using a loop and an if() test at each iteration. Instead, use the built-in exists() function, which returns Boolean true if a key match occurs.
One-Dimension Array Operations
Create an empty array:
@myarray = ( );
Create a filled array:
@myarray = ($var0, $var1, $var2, …);
Get the length of an array:
$arrlen = @myarray;
or
$arrlen = $#myarray + 1;
Fetch a specific single member in an array:
$myscalar = $myarray[$index];
Fetch a contiguous set of members in an array (‘ .. ‘ is literal):
@newarray = @myarray[$idx_beg .. $idx_end];
Fetch specific members in an array:
@newarray = @myarray[$idx1, $idx2, $idx3, …];
Set a specific single member in an array:
$myarray[$index] = $myscalar;
Set a contiguous set of members in an array (‘ .. ‘ is literal):
@myarray[$idx_beg .. $idx_end] = @replac;
Set specific members in an array:
@myarray[$idx1, $idx2, $idx3, …] = @replac;
Remove but save the scalar from the beginning of an array:
$value = shift (@myarray);
Insert a scalar at the beginning of an array (returns new size):
$newlen = unshift (@myarray, $myvar);
Insert one array at the beginning of another existing one (returns new size):
$newlen = unshift (@another, @one_array);
Remove but save the scalar at the end of an array:
$value = pop (@myarray);
Add a value at the end of an array (returns new size):
$newlen = push (@myarray, $myvar);
Append one array to another existing one (returns new size):
$newlen = push (@another, @one_array);
Delete everyting from an array and lose it all:
%myarray = ();
Delete everyting from an array but save it for later:
@rem_data = splice (@myarray);
Delete everything from a specified position and later:
@rem_data = splice (@myarray,$first_del);
pop (@myarray); is same as splice (@myarray, -1);
Delete several elements from a specified position and later:
@rem_data = splice (@myarray, $first_del, $num_dels);
pop (@myarray); is same as splice (@myarray, $#myarray, 1);
shift (@myarray); is same as splice (@myarray, 0, 1);
Delete several elements from a specified position and later, then replace with data from a list:
@rem_data = shift (@myarray, $first_del, $num_dels, $replac1, $replac2, …);
or
@rem_data = shift (@myarray, $first_del, $num_dels, @replac);
Multi-Dimension Arrays
In a 2-dimension array, the first dimension is a set of references to arrays, and each reference yields a 1-D array of scalar values for the second dimension. In a 3-D array, the first and second dimensions are sets of references to arrays, and the last dimension is a set of scalar values.
Create a filled 2-D array (2r x 3c):
@veca = {[$r0c0,$r0c1], [$r1c0,$r1c1], [$r2c0,$r2c1]};
Fill in a single row from another 1-D array:
$veca[$rownum] = [ @row ];
Fetch a single row:
@row = @{$veca[$rownum]};
or
@row = @$veca[$rownum];
Fetch a single member:
$val = ${$veca[$rownum]}->[$colnum];
or
$val = $veca[$rownum]->[$colnum];
or
$val = $veca[$rownum][$colnum];
Number of rows (length of the first dimension):
@n_rows = $#veca + 1;
Number of columns in a row:
@n_cols = $#{$veca[$rownum]};
Hash Operations
Create an empty hash:
%myhash = { };
Create a filled hash:
%myhash = ($key1, $val1, $key2, $val2, …);
or
%myhash = ($key1 => $val1, $key2 => $val2, …);
Fetch a hash value from a known key:
$the_val = $myhash{$the_key};
Fetch a several hash values at once
@val_list = @myhash{$key1, $key2, $key3, …};
Create a reference to an anonymous filled hash:
$hashref = {$key1 => $val1, $key2 => $val2, …};
for example
$record[$rec_num] = {name => $val1, rank => $val2, sernum => $val3};
then
$this_rank = $record[$this_rec_num]->{‘rank’};
Test if a particular key exists in a hash:
$is_there = exists ($myhash{$the_key});
Test if a particular key has its corresponding value defined (not undef):
$has_value = defined ($myhash{$the_key});
Get a list of all keys:
@keylist = keys (%myhash);
Get a list of all values (same order as keys):
@valuelist = values (%myhash);
Remove a key/value pair but save it elsewhere for later:
%removed = delete ($myhash{$delkey});
Manipulating Perl Arrays
Now that you have seen the basics of arrays, you’ll want to see how to change and manipulate an array or the elements of an array. The first thing we will look at is changing and adding elements.
Changing & Adding Elements
To change an array element, you can just access it with its list number and assign it a new value:
@browser = (“NS”, “IE”, “Opera”);
$browser[2]=”Mosaic”;
This changes the value of the element with the list number two (remember, arrays start counting at zero- so the element with the list number two is actually the third element). So, we changed “Opera” to “Mosaic”, thus the array now contains “NS”, “IE”, and “Mosaic”.
Now, suppose we want to add a new element to the array. We can add a new element in the last position by just assigning the next position a value. If it doesn’t exist, it is added on to the end:
@browser = (“NS”, “IE”, “Opera”);
$browser[3]=”Mosaic”;
Now, the array has four elements: “NS”, “IE”, “Opera”, and “Mosaic”.
Splice Function
Using the splice function, you can delete or replace elements within the array. For instance, if you simply want to delete an element, you could write:
@browser = (“NS”, “IE”, “Opera”);
splice(@browser, 1, 1);
You’ll see three arguments inside the () of the splice function above. The first one is just the name of the array you want to splice. The second is the list number of the element where you wish to start the splice (starts counting at zero). The third is the number of elements you wish to splice. In this case, we just want to splice one element. The code above deletes the element at list number 1, which is “IE” (NS is zero, IE is 1, Opera is 2). So now the array has only “NS” and “Opera”.
If you want to delete more than one element, change that third number to the number of elements you wish to delete. Let’s say we want to get rid of both “NS” and “IE”. We could write:
@browser = (“NS”, “IE”, “Opera”);
splice(@browser, 0, 2);
Now, it starts splicing at list number zero, and continues until it splices two elements in a row. Now all that will be left in the array is “Opera”.
You can also use splice to replace elements. You just need to list your replacement elements after your other three arguments within the splice function. So, if we wanted to replace “IE” and “Opera” with “NeoPlanet” and “Mosaic”, we would write it this way:
@browser = (“NS”, “IE”, “Opera”);
splice(@browser, 1, 2, “NeoPlanet”, “Mosaic”);
Now the array contains the elements “NS”, “NeoPlanet”, and “Mosaic”. As you can see, the splice function can come in handy if you need to make large deletions or replacements.
Unshift/Shift
If you want to simply add or delete an element from the left side of an array (element zero), you can use the unshift and shift functions. To add an element to the left side, you would use the unshift function and write something like this:
@browser = (“NS”, “IE”, “Opera”);
unshift(@browser, “Mosaic”);
As you can see, the first argument tells you which array to operate on, and the second lets you specify an element to be added to the array. So, “Mosaic” takes over position zero and the array now has the four elements “Mosaic”, “NS”, “IE”, and “Opera”.
To delete an element from the left side, you would use the shift function. All you have to do here is give the array name as an argument, and the element on the left side is deleted:
@browser = (“NS”, “IE”, “Opera”);
shift(@browser);
Now, the array has only two elements: “IE” and “Opera”.
You can keep the value you deleted from the array by assigning the shift function to a variable:
@browser = (“NS”, “IE”, “Opera”);
$old_first_element= shift(@browser);
Now the array has only “IE” and “Opera”, but you have the variable $old_first_element with the value of “NS” so you can make use of it after taking it from the array.
Push/Pop
These two functions are just like unshift and shift, except they add or delete from the right side of an array (the last position). So, if you want to add an element to the end of an array, you would use the push function:
@browser = (“NS”, “IE”, “Opera”);
push(@browser, “Mosaic”);
Now, you have an array with “NS”, “IE”, “Opera”, and Mosaic”.
To delete from the right side, you would use the pop function:
@browser = (“NS”, “IE”, “Opera”);
pop(@browser);
Now you have an array with just “NS” and “IE”.
You can keep the value you deleted from the array by assigning the pop function to a variable:
@browser = (“NS”, “IE”, “Opera”);
$last_element= pop(@browser);
Now the array has only “NS” and “IE”, but you have the variable $last_element with the value of “Opera” so you can make use of it after taking it from the array.
Chop & Chomp
If you want to take the last character of each element in an array and “chop it off”, or delete it, you can use the chop function. It would look something like this:
@browser = (“NS4”, “IE5”, “Opera3”);
chop(@browser);
This code would take the numbers off the end of each element, so we would be left with “NS”, “IE” and “Opera”.
If you want to remove newline characters from the end of each array element, you can use the chomp function. This comes in handy later when we are reading from a file, where we would need to chomp the new line (\n) character from each line in a file. Here is a more simplified example for now:
@browser = (“NS4\n”, “IE5\n”, “Opera3\n”);
chomp(@browser);
This code takes off the \n characters from the end of each element, leaving us with NS4, IE5, and Opera3.
Sort
If you want to sort the elements of an array, this can come in handy. You can sort in ascending or descending order with numbers or strings. Numbers will go by the size of the number, strings will go in alphabetical order.
@browser = (“NS”, “IE”, “Opera”);
sort (ascend @browser);
sub ascend
{
$a <=> $b;
}
The sub from above is a subroutine, much like what is called a “function” in other languages. We will explain that in more detail later. As you can see, the code above would sort in ascending order, so it would sort our array in alphabetical order. So, we have: “IE”, “NS”, and “Opera” as the new order. If you want it in reverse alphabetical order, you would use $b <=> $a in place of the $a <=> $b above. You could change the name of the subroutine to whatever you wish, just be sure you call the subroutine with the same name. This will make a bit more sense after we get to the section on subroutines and reading from files.
Reverse
You can reverse the order of the array elements with the reverse function. You would just write:
@browser = (“NS”, “IE”, “Opera”);
reverse(@browser);
Now, the order changes to “Opera”, “IE”, and “NS”.
Join
You can create a flat file database from your array with the join function. Again, this is more useful if you are reading and writing form files. For now, what you will want to know is that it allows you to use a delimiter (a character of your choice) to separate array elements. The function creates a variable for each element, joined by your delimiter. So, if you want to place a colon (:) between each element, you would write:
@browser = (“NS”, “IE”, “Opera”);
join(“:”, @browser);
This would create something like this:
NS:IE:Opera
Split
The split function is very handy when dealing with strings. It allows you to create an array of elements by splitting a string every time a certain delimiter (a character of your choice) shows up within the string. Suppose we had the string:
NS:IE:Opera
Using the split function, we could create an array with the elements “NS”, “IE”, and “Opera” by splitting the string on the colon delimiter (:). We could write:
$browser_list=”NS:IE:Opera”;
@browser= split(/:/, $browser_list);
Notice in the split function that you place your delimiter between two forward slashes. You then place the string you want to split as the second argument, in this case the string was the value of the $browser_list variable. Setting it equal to @browser creates the @browser array from the split.
Well, that should be enough to keep us all busy for a while. You can do a whole bunch of things with arrays, and we’ll be using them extensively in later sections. So, have fun with what we have so far, we’ll be moving on soon!
Well, that’s it for now. Let’s go on to: Associative Arrays.