- 5.1 More About Data Types
- 5.2 Scalars, Arrays, and Hashes
- 5.3 Array Functions
- 5.4 Hash (Associative Array) Functions
- 5.5 What You Should Know
- 5.6 What's Next?
- Exercise 5: The Funny Characters
5.4 Hash (Associative Array) Functions
5.4.1 The keys Function
The keys function returns, in random order, an array whose elements are the keys of a hash (see also Section 5.4.2, “The values Function,” and Section 5.4.3, “The each Function”). Starting with Perl 5.12, keys also returns the index values of an array. In scalar context, it returns the number of keys (or indices).
Format
keys(ASSOC_ARRAY) keys ASSOC_ARRAY
Example 5.44
(In Script) use warnings; my(%weekday, @daynumber, $key); # The keys function returns the keys of a hash 1 my %weekday= ( '1'=>'Monday', '2'=>'Tuesday', '3'=>'Wednesday', '4'=>'Thursday', '5'=>'Friday', '6'=>'Saturday', '7'=>'Sunday', ); 2 my @daynumber = keys(%weekday); 3 print "@daynumber\n"; 4 foreach $key ( keys(%weekday) ){print "$key ";} print "\n"; 5 foreach $key ( sort keys(%weekday) ){print "$key ";} print "\n"; (Output) 6 4 1 3 7 2 5 6 4 1 3 7 2 5 1 2 3 4 5 6 7
Explanation
- 1. The hash %weekday is assigned keys and values.
- 2. The keys function returns a list of all the keys in a hash. In this example, @daynumber is an unordered list of all the keys in the %weekday hash.
- 4. The keys function returns a list of keys. The foreach loop will traverse the list of keys, one at a time, printing the keys.
- 5. The keys function returns a list of keys in %weekday hash. The list will then be sorted, and finally the foreach loop will traverse the sorted list of keys, one at a time, printing each key.
5.4.2 The values Function
The values function returns, in random order, a list consisting of all the values of a named hash. (After Perl 5.12, it will also return the values of an array.) In scalar context, it returns the number of values.
Format
values(ASSOC_ARRAY) values ASSOC_ARRAY
Example 5.45
(In Script) use warnings; # The values function returns the values in a hash 1 my %weekday= ( '1'=>'Monday', '2'=>'Tuesday', '3'=>'Wednesday', '4'=>'Thursday', '5'=>'Friday', '6'=>'Saturday', '7'=>'Sunday', ); 2 foreach my $val ( values(%weekday)){print "$val";} print "\n"; (Output) 2 Saturday Thursday Monday Wednesday Sunday Tuesday Friday
Explanation
- 1. The hash %weekday is assigned keys and values.
- 2. The values function returns a list of values from the hash %weekday. The foreach is used to loop through the list of values, one at a time, using $val as its loop variable.
Since hashes are stored in a random order, to get the hash values in the order in which they were assigned, you can use a hash slice as shown in the following example.
Example 5.46
(In Script) use warnings; # Use a hash slice to get the values returned in order. 1 my %weekday= ( '1'=>'Monday', '2'=>'Tuesday', '3'=>'Wednesday', '4'=>'Thursday', '5'=>'Friday', '6'=>'Saturday', '7'=>'Sunday', ); 2 my @days = @weekday{1..7}; print "@days\n"; (Output) 2 Monday Tuesday Wednesday Thursday Friday Saturday Sunday
Explanation
- The hash %weekday is assigned keys and values.
- CA hash slice is a way of referring to one or more elements of the hash in one statement, to get a list of values, or to assign a list of values, and because it is using a list of keys, the list is preceded by the @ sign and the list is enclosed in curly braces to indicate that your are indexing a hash.*
5.4.3 The each Function
The each function returns, in random order, a two-element list whose elements are the key and the corresponding value of a hash. It must be called multiple times to get each key/value pair, as it only returns one set each time it is called, somewhat like reading lines from a file, one at a time.
Format
each(ASSOC_ARRAY) each ASSOC_ARRAY
Example 5.47
(In Script) use warnings; my(%weekday $key, $value); # The each function retrieves both keys and values from a hash 1 %weekday=( 'Mon' => 'Monday', 'Tue' => 'Tuesday', 'Wed' => 'Wednesday', 'Thu' => 'Thursday', 'Fri' => 'Friday', 'Sat' => 'Saturday', 'Sun' => 'Sunday', ); 2 while(($key,$value)=each(%weekday)){ 3 print "$key = $value\n"; } (Output) 3 Sat = Saturday Fri = Friday Sun = Sunday Thu = Thursday Wed = Wednesday Tue = Tuesday Mon = Monday
Explanation
- The hash %weekday is assigned keys and values.
- The each function returns a list consisting of each key and its associated value from the %weekday hash. They are assigned to the scalars $key and $value, respectively.
The keys and values are printed, but in an unordered way. You can order them as shown in Example 5.46 or use a foreach loop with an ordered list of keys:
foreach $key( 1..7){ print $weekday{$key},"\n"; }
5.4.4 Removing Duplicates from a List with a Hash
Earlier, we used a hash to remove duplicate entries in an array. In the following example, the built-in map function is used to map each element of an array into a hash to create unique hash keys.
Example 5.48
(The Script) use warnings; my(@list, @uniq); # Using the map function with a hash @list = qw/a b c d d a e b a b d e f/; 1 @uniq = keys %{{ map {$_ => 1 } @list }}; 2 print "@list\n@uniq\n"; (Output) a b c d d a e b a b d e f e c a b d f
Explanation
- The map function iterates through the values in the @list array to create a hash where each element in @list becomes a key, $_, to an unnamed hash with each key getting a corresponding value of 1. After the hash is created, the built-in keys function returns a list of the unique keys which are assigned to the array @uniq.
- Both the original list, @list, and the new list, @uniq, are printed, showing that the duplicate values in the original list have been removed.
5.4.5 Sorting a Hash by Keys and Values
When sorting a hash, you can sort the keys alphabetically very easily by using the built-in sort command, as we did with arrays in the preceding section. But you may want to sort the keys numerically or sort the hash by its values. To do this requires a little more work.
You can define a subroutine to compare the keys or values. (See Chapter 11, “How Do Subroutines Function?”) The subroutine will be called by the built-in sort function. It will be sent a list of keys or values to be compared. The comparison is either an ASCII (alphabetic) or a numeric comparison, depending upon the operator used. The cmp operator is used for comparing strings, and the <=> operator is used for comparing numbers. The reserved global scalars $a, and $b are used in the subroutine to hold the values as they are being compared. The names of these scalars cannot be changed.
Sort Hash by Keys in Ascending Order.
To perform an ASCII, or alphabetic, sort on the keys in a hash is relatively easy. Perl’s sort function is given a list of keys and returns them sorted in ascending order. A foreach loop is used to loop through the hash keys, one key at a time.
Example 5.49
(In Script) use warnings; 1 my %wins = ( "Portland Panthers" => 10, "Sunnyvale Sluggers" => 12, "Chico Wildcats" => 5, "Stevensville Tigers" => 6, "Lewiston Blazers" => 11, "Danville Terriors" => 8, ); print "\n\tSort Teams in Ascending Order:\n\n"; 2 foreach my $key(sort keys %wins) { 3 printf "\t% -20s%5d\n", $key, $wins{$key}; } (Output) Sort Teams in Ascending Order: Chico Wildcats 5 Danville Terriors 8 Lewiston Blazers 11 Portland Panthers 10 Stevensville Tigers 6 Sunnyvale Sluggers 12
Explanation
- A hash called %wins is assigned key/value pairs.
- The foreach loop will be used to iterate through each of an alphabetically sorted list of keys from a hash called %wins.
- The printf() function formats and prints the sorted keys and its values.
Sort Hash by Keys in Reverse Order.
To sort a hash by keys alphabetically and in descending order, just add the built-in reverse function to the previous example. The foreach loop is used to get each key from the hash, one at a time, after the reversed sort.
Example 5.50
(In Script) use warnings; 1 my %wins = ( "Portland Panthers" => 10, "Sunnyvale Sluggers" => 12, "Chico Wildcats" => 5, "Stevensville Tigers" => 6, "Lewiston Blazers" => 11, "Danville Terriors" => 8, ); print "\n\tSort Teams in Descending/Reverse Order:\n\n"; 2 foreach my $key (reverse sort keys %wins) { 3 printf "\t% -20s%5d\n", $key, $wins{$key}; } (Output) Sort Teams in Descending/Reverse Order: Sunnyvale Sluggers 12 Stevensville Tigers 6 Portland Panthers 10 Lewiston Blazers 11 Danville Terriors 8 Chico Wildcats 5
Explanation
- A hash called %wins is assigned key/value pairs.
- The foreach loop will be used to iterate through each of the elements in the hash. The reverse function takes the alphabetically sorted list returned from the sort function and reverses it.
- The printf() function formats and prints the keys and sorted values.
Sort Hash by Keys Numerically.
A user-defined subroutine is used to sort a hash by keys numerically. In the subroutine, Perl’s special $a and $b variables are used to hold the value being compared with the appropriate operator. For numeric comparison, the <=> operator is used, and for string comparison, the cmp operator is used. The sort function will send a list of keys to the user-defined subroutine. The sorted list is returned.
Example 5.51
(In Script) use warnings; 1 sub desc_sort_subject { 2 $b <=> $a; # Numeric sort descending } 3 sub asc_sort_subject{ 4 $a <=> $b; # Numeric sort ascending } 5 my %courses = ( "101" => "Intro to Computer Science", "221" => "Linguistics", "300" => "Astronomy", "102" => "Perl", "103" => "PHP", "200" => "Language arts", ); print "\n\tCourses in Ascending Numeric Order:\n"; 6 foreach my $key (sort asc_sort_subject(keys %courses)) { 7 printf "\t%-5d%s\n", $key, $courses{"$key"}; } 8 print "\n\tCourses in Descending Numeric Order:\n"; foreach my $key (sort desc_sort_subject(keys %courses)) { printf "\t%-5d%s\n", $key, $courses{"$key"}; } (Output) Courses in Ascending Numeric Order: 101 Intro to Computer Science 102 Perl 103 PHP 200 Language arts 221 Linguistics 300 Astronomy Courses in Descending Numeric Order: 300 Astronomy 221 Linguistics 200 Language arts 103 PHP 102 Perl 101 Intro to Computer Science
Explanation
- 1. This is a user-defined subroutine called desc_sort_subject. When its name is given to the sort function, this function will be used to compare the keys passed to it. It will sort the keys numerically.
- 2. The special Perl variables $a and $b are used to compare the values of the keys from the hash called %courses. The <=> operator is a numeric comparison operator that will compare each of the keys to be sorted as numbers. In the previous examples, we sorted the keys alphabetically. Since $b precedes $a, the sort is descending.
- 3. This is also a user-defined subroutine called asc_sort_subject. This function is identical to the previous function on line 1, except it will sort the keys of the hash in ascending numeric order rather than descending.
- 4. In this function, the special variables $a and $b have been reversed, causing the sort after the comparison to be in ascending order.
- 5. The hash called %courses is defined with key/value pairs.
- 6. The foreach loop will be used to iterate through each of the keys in the hash. It receives its list from the output of the sort command.
- 7, 8. The printf function formats and prints the keys and sorted values.
Numerically Sort a Hash by Values in Ascending Order.
To sort a hash by its values, a user-defined function is also defined. The values of the hash are compared by the special variables $a and $b. If $a is on the left-hand side of the comparison operator, the sort is in ascending order, and if $b is on the left-hand side, then the sort is in descending order. The <=> operator compares its operands numerically.
Example 5.52
(In Script) use warnings; 1 sub asc_sort_wins { 2 $wins{$a} <=> $wins{$b}; } 3 my %wins = ( "Portland Panthers" => 10, "Sunnyvale Sluggers" => 12, "Chico Wildcats" => 5, "Stevensville Tigers" => 6, "Lewiston Blazers" => 11, "Danville Terriors" => 8, ); print "\n\tWins in Ascending Numeric Order:\n\n"; 4 foreach my $key (sort asc_sort_wins(keys %wins)) { 5 printf "\t% -20s%5d\n", $key, $wins{$key}; } (Output) Wins in Ascending Numeric Order: Chico Wildcats 5 Stevensville Tigers 6 Danville Terriors 8 Portland Panthers 10 Lewiston Blazers 11 Sunnyvale Sluggers 12
Explanation
- This is a user-defined subroutine called asc_sort_wins. When its name is given to the sort function, this function will be used to compare the hash values passed to it. It will sort the values by value, numerically.
- The special Perl variables $a and $b are used to compare the values of the hash called $wins. The <=> operator is a numeric comparison operator that will compare each of the values to be sorted. To compare strings, the cmp operator is used.
- The hash called %wins is assigned key/value pairs.
- The foreach loop iterates through each of the elements in the hash. It receives its list from what is returned from the sort function.
- The printf function formats and prints the keys and sorted values.
Numerically Sort a Hash by Values in Descending Order.
To sort a hash numerically and in descending order by its values, a user-defined function is created as in the previous example. However, this time the $b variable is on the left-hand side of the <=> numeric operator, and the $a variable is on the right-hand side. This causes the sort function to sort in descending order.
Example 5.53
(In Script) use warnings; # Sorting a hash by value in descending order 1 sub desc_sort_wins { 2 $wins{$b} <=> $wins{$a}; # Reverse $a and $b } 3 my %wins = ( "Portland Panthers" => 10, "Sunnyvale Sluggers" => 12, "Chico Wildcats" => 5, "Stevensville Tigers" => 6, "Lewiston Blazers" => 11, "Danville Terriors" => 8, ); print "\n\tWins in Descending Numeric Order:\n\n"; 4 foreach my $key (sort desc_sort_wins(keys %wins)){ 5 printf "\t% -20s%5d\n", $key, $wins{$key}; } (Output) Wins in Descending Numeric Order: Sunnyvale Sluggers 12 Lewiston Blazers 11 Portland Panthers 10 Danville Terriors 8 Stevensville Tigers 6 Chico Wildcats 5
Explanation
- This is a user-defined subroutine called desc_sort_wins. When its name is given to the sort function, this function will be used to compare the hash values passed to it. It will sort the values by value, numerically but in descending order.
- The special Perl variables $a and $b are used to compare the values of the hash called $wins. The position of $a and $b determines whether the sort is in ascending or descending order. If $a is on the left-hand side of the <=> operator, the sort is a numeric ascending sort; if $b is on the left-hand side of the <=> operator, the sort is descending. To compare strings, the cmp operator is used.
- The hash called %wins is assigned key/value pairs.
- The foreach loop will be used to iterate through each of the keys in the hash. It receives its list from what is returned from the sort function.
- The printf function formats and prints the keys and sorted values.
5.4.6 The delete Function
The delete function deletes a specified element from a hash. The deleted value is returned if successful.5
Example 5.54
(In Script) use warnings; 1 my %employees=( "Nightwatchman" => "Joe Blow", "Janitor" => "Teddy Plunger", "Clerk" => "Sally Olivetti", ); 2 my $layoff=delete $employees{"Janitor"}; print "We had to let $layoff go.\n"; print "Our remaining staff includes: "; print "\n"; while((my $key, my $value)=each %employees){ print "$key: $value\n"; } (Output) We had to let Teddy Plunger go. Our remaining staff includes: Nightwatchman: Joe Blow Clerk: Sally Olivetti
Explanation
- A hash is defined with three key/value pairs.
- The delete function deletes an element from the specified hash by specifying the key. Janitor is the key. Both key and value are removed. The hash value associated with the key Janitor is removed and returned. The value Teddy Plunger is returned and assigned to the scalar $layoff.
5.4.7 The exists Function
The exists function returns true if a hash key (or array index) exists, and false if not.
Format
exists $ASSOC_ARRAY{KEY}
Example 5.55
use warnings; 1 my %employees=( "Nightwatchman" => "Joe Blow", "Janitor" => "Teddy Plunger", "Clerk" => "Sally Olivetti", ); 2 print "The Nightwatchman exists.\n" if exists $employees{"Nightwatchman"}; 3 print "The Clerk exists.\n" if exists $employees{"Clerk"}; 4 print "The Boss does not exist.\n" if not exists $employees{"Boss"}; (Output) 2 The Nightwatchman exists. 3 The Clerk exists. 4 The Boss does not exist.
Explanation
- A hash is defined with three key/value pairs.
- If a key “Nightwatchman” exists, the exists function returns true.
- If a key “Clerk” exists, the exists function returns true.
- If the key “Clerk” does not exist, the inverted value of the exists function is false.
5.4.8 Special Hashes
The %ENV Hash.
The %ENV hash contains the environment variables handed to Perl from the parent process; for example, a shell or a Web server. The key is the name of the environment variable, and the value is what was assigned to it. If you change the value of %ENV, you will alter the environment for your Perl script and any processes spawned from it, but not the parent process. Environment variables play a significant roll in CGI Perl scripts.
Example 5.56
(In Script) use warnings; 1 foreach my $key (keys %ENV){ 2 print "$key\n"; } 3 print "\nYour login name $ENV{'LOGNAME'}\n"; 4 my $pwd = $ENV{'PWD'}; 5 print "\n", $pwd, "\n"; (Output) 2 OPENWINHOME MANPATH FONTPATH LOGNAME USER TERMCAP TERM SHELL PWD HOME PATH WINDOW_PARENT WMGR_ENV_PLACEHOLDER 3 Your login name is ellie 5 /home/jody/home
Explanation
- 1. The foreach loop iterates through the keys of the %ENV hash.
- 3. Print the value of the key LOGNAME.
- 4. Assign the value of the key PWD to $pwd.
- 5. Print the value of $pwd, the present working directory.
The %SIG Hash.
The %SIG hash allows you to set signal handlers for signals. If, for example, you press <CTRL>+C when your program is running, that is a signal, identified by the name SIGINT. (See UNIX manual pages for a complete list of signals.) The default action of SIGINT is to interrupt your process. The signal handler is a subroutine that is automatically called when a signal is sent to the process. Normally, the handler is used to perform a clean-up operation or to check some flag value before the script aborts. (All signal handlers are assumed to be set in the main package.)
The %SIG hash contains values only for signals set within the Perl script.
Example 5.57
(In Script) use warnings; 1 sub handler{ 2 local($sig) = @_; # First argument is signal name 3 print "Caught SIG$sig -- shutting down\n"; exit(0); } 4 SIG{'INT'} = 'handler'; # Catch <CTRL>+C print "Here I am!\n"; 5 sleep(10); 6 $SIG{'INT'}='DEFAULT'; 7 $SIG{'INT'}='IGNORE'; < Program continues here >
Explanation
- handler is the name of the subroutine. The subroutine is defined.
- $sig is a local variable and will be assigned the signal name.
- When the SIGINT signal arrives, this message will appear, and the script will exit.
- The value assigned to the key INT is the name of the subroutine, handler. When the signal arrives, the handler is called.
- The sleep function gives you 10 seconds to press <CTRL>+C to see what happens.
- The default action is restored. The default action is to abort the process if the user presses <CTRL>+C.
- If you assign the value IGNORE to the $SIG hash, then <CTRL>+C will be completely ignored and the program will continue.
The %INC Hash.
The %INC hash contains the entries for each filename that has been included via the use or require functions. The key is the filename; the value is the location of the actual file found.
5.4.9 Context Revisited
In summary, the way Perl evaluates variables depends on how the variables are being used; they are evaluated by context, either scalar, list, or void.
If the value on the left-hand side of an assignment statement is a scalar, the expression on the right-hand side is evaluated in a scalar context; whereas if the value on the left-hand side is an array, the right-hand side is evaluated in a list context.
Void context is a special form of scalar context. It is defined by the Perl monks as a “context that doesn’t have an operator working on it. The value of a thing in void context is discarded, not used for anything...” An example of void context is when you assign a list to a scalar separating the elements with a comma. The comma operator evaluates its left argument in void context, throws it away, then evaluates the right argument, and so on, until it reaches the end of the list, discarding all but the last one.
$fruit = ("apple","pear","peach"); # $fruit is assigned "peach"; # "apple" and "pear" are discarded # as useless use in void context
You’ll see examples throughout the rest of this book where context plays a major role.
Example 5.58
(The perldoc function describes how reverse works) 1 $ perldoc -f reverse reverse LIST In list context, returns a list value consisting of the elements of LIST in the opposite order. In scalar context, concatenates the elements of LIST and returns a string value with all characters in the opposite order. ......
Example 5.59
(The Perl Script) use warnings; 1 my @list = (90,89,78,100,87); 2 my $str="Hello, world"; 3 print "Original array: @list\n"; 4 print "Original string: $str\n"; 5 my @revlist = reverse @list; 6 my $revstr = reverse $str; 7 print "Reversed array is: @revlist\n"; 8 print "Reversed string is: $revstr\n"; 9 my $newstring = reverse @list; 10 print "List reversed, context string: $newstring\n"; 11 "Later, going into the Void!!!!\n"; # Void context (Output) 11 Useless use of a constant ("Later, going into the void\n") in void context at Example line 13. 3 Original array: 90 89 78 100 87 4 Original string: Hello, world 7 Reversed array is: 87 100 78 89 90 8 Reversed string is: dlrow ,olleH 10 List reversed, context string: 78001879809
Explanation
- 11. This is a case where you will see a warning message about using void context when you have a string constant that is not being used in assignment, print out, or doesn’t return anything, and appears to be doing nothing. It doesn’t have any side effects and doesn’t break the program, but demonstrates a case where Perl views void context.
- 5. Context is demonstrated in the documentation for Perl’s built-in reverse function.
- 6. The reverse function reverses the elements of an array and returns the reversed elements to another array. Context is list.
- 8. This time, the reverse function reverses the characters in a string. It returns the reverse string as a scalar. Context is scalar.
- 9. Here the reverse function reverses the array again, but the returned value will be assigned to a string. The context being scalar, the function will reverse the array elements and convert the list into a string of characters.