5.2 Scalars, Arrays, and Hashes
Now that we have discussed the basics of Perl variables (types, visibility, funny characters, and so forth), we can look at them in more depth. Perhaps a review of the quoting rules detailed in Chapter 4, “Getting a Handle on Printing,” would be helpful at this time.
5.2.1 Scalar Variables
Scalar variables hold a single number or string3 and are preceded by a dollar sign ($). Perl scalars need a preceding dollar sign whenever the variable is referenced, even when the scalar is being assigned a value.
Assignment.
When making an assignment, the value on the right-hand side of the equal sign is evaluated as a single value (that is, its context is scalar). A quoted string, then, is considered a single value even if it contains many words.
Example 5.4
1 $number = 150; # Number 2 $name = "Jody Savage"; # String 3 $today = localtime(); # Function
Explanation
- 1. The numeric literal, 150, is assigned to the scalar variable $number.
- 2. The string literal Jody Savage is assigned to the scalar $name as a single string.
- 3. The output of Perl’s localtime function will be assigned as a string to $today. (The return value of localtime is string context here and if assigned to an array its return value is an array of numbers. See perldoc -f localtime.)
Example 5.5
(The Script) use warnings; # Initializing scalars and printing their values 1 my $num = 5; 2 my $friend = "John Smith"; 3 my $money = 125.75; 4 my $now = localtime; # localtime is a Perl function 5 my $month="Jan"; 6 print "$num\n"; 7 print "$friend\n"; 8 print "I need \$$money.\n"; # Protecting our money 9 print qq/$friend gave me \$$money.\n/; 10 print qq/The time is $now\n/; 11 print "The month is ${month}uary.\n"; # Curly braces shield # the variable 12 print "The month is $month" . "uary.\n"; # Concatenate (Output) 6 5 7 John Smith 8 I need $125.75. 9 John Smith gave me $125.75. 10 The time is Sat Jan 24 16:12:49 2014. 11 The month is January. 12 The month is January.
Explanation
- 1. The scalar $num is assigned the numeric literal, 5.
- 2. The scalar $friend is assigned the string literal, John Smith.
- 3. The scalar $money is assigned the numeric floating point literal, 125.75.
- 4. The scalar $now is assigned the output of Perl’s built-in localtime function.
- 5. The scalar $month is assigned Jan.
- 8. The quoted string is printed. The backslash allows the first dollar sign ($) to be printed literally; the value of $money is interpolated within double quotes, and its value printed.
- 9. The Perl qq construct replaces double quotes. The string to be quoted is enclosed in forward slashes. The value of the scalar $friend is interpolated; a literal dollar sign precedes the value of the scalar interpolated variable, $money.
- 10. The quoted string is printed as if in double quotes. The $now variable is interpolated.
- 11. Curly braces can be used to shield the variable from characters that are appended to it. January will be printed.
- 12. Normally, two strings or expressions are joined together with the dot operator (see Chapter 6, “Where’s the Operator?”), called the concatenation operator.
The defined Function.
If a scalar has neither a valid string nor a valid numeric value, it is undefined. The defined function allows you to check for the validity of a variable’s value. It returns 1 if the variable has a value (other than undef) and nothing if it does not.
Example 5.6
. $name="Tommy"; print "OK \n" if defined $name;
The undef Function.
When you define a variable without giving it a value, such as
my $name;
the initial value is undef.
You can use the undef function to undefine an already defined variable. It releases whatever memory that was allocated for the variable. The function returns the undefined value. This function also releases storage associated with arrays and subroutines.
Example 5.7
undef $name;
The $_ Scalar Variable.
The $_ (called a topic variable4) is a ubiquitous little character. Although it is very useful in Perl scripts, it is often not seen, somewhat like your shadow—sometimes you see it; sometimes you don’t. It is used as the default pattern space for searches, for functions that require a scalar argument, and to hold the current line when looping through a file. Once a value is assigned to $_, functions such as chomp, split, and print will use $_ as an argument. You will learn more about functions and their arguments later, but for now, consider the following example.
Example 5.8
1 $_ = "Donald Duck\n"; 2 chomp; # The newline is removed from $_ 3 print; # The value of $_ is printed (Output) Donald Duck
Explanation
- 1. The $_ scalar variable is assigned the string “Donald Duck\n”. Now you see it!
- 2. The chomp function removes the newline from $_, the default scalar. Now you don’t!
- 3. The print function has been given nothing to print, so it will print $_, the default scalar, without a trailing newline.
The $_ Scalar and Reading Input from Files
When looping through a file, the $_ is often used as a holding place for each line as it is read. In the following example, a text file called datebook.txt is opened for reading. The filehandle is $fh, a user-defined variable to represent the real file, datebook.txt. Each time the loop is entered, a line is read from the file. But where does the line go? It is implicitly assigned to the $_ variable. The next time the loop is entered, a new line is read from the file and assigned to $_, overwriting the previous line stored there. The loop ends when the end of file is reached. The print function, although it appears to be printing nothing, will print the value of $_ each time the loop block is entered.
Example 5.9
(The Script) use warnings; # Reading input from a file 1 open(my $fh, "<", "datebook.txt") or die $!; 2 while(<$fh>){ # loops through the file a line at a time storing # each line in $_ 3 print; # prints the value stored in $_ 4 } 5 close $fh; (Output) Jon DeLoach:408-253-3122:123 Park St., San Jose, CA 04086:7/25/53:85100 Karen Evich:284-758-2857:23 Edgecliff Place, Lincoln, NB 92086:7/25/53:85100 Karen Evich:284-758-2867:23 Edgecliff Place, Lincoln, NB 92743:11/3/35:58200 Karen Evich:284-758-2867:23 Edgecliff Place, Lincoln, NB 92743:11/3/35:58200 Fred Fardbarkle:674-843-1385:20 Parak Lane, DeLuth, MN 23850:4/12/23:780900
Explanation
- 1. A user-defined filehandle is a Perl way of associating a real file with an internal Perl structure by a name. In this example, $fh is a lexically scoped filehandle used to represent the real file, datebook.txt, which is opened for reading. If the file doesn’t exist or is unreadable, the program will “die” (exit) with the reason it died ($!).
- 2. The while loop is entered. Perl will read the first line from the file and implicitly assign its value to $_, and if successful enter the body of the loop. The angle brackets (<>) are used for reading, as we saw when reading from STDIN.
- 3. Every time the loop is entered, a new line from the file is stored in $_, overwriting the previous line that was stored there, and each time the current value of $_ is printed.
- 4. This is the closing brace for the block of the loop. When the file has no more lines, the read will fail, and the loop will end.
- 5. Once finished with the file, it is closed via the filehandle. (See Chapter 10, “Getting a Handle on Files,” for a complete discussion on filehandles.)
5.2.2 Arrays
Let’s say when you moved into town, you made one friend. That friend can be stored in a scalar as $friend=“John”. Now let’s say a few months have gone by since you moved, and now you have a whole bunch of new friends. In that case, you could create a list of friends, give the list one name, and store your friends in a Perl array; for example, @pals=(“John”, “Mary”, “Sanjay”, “Archie”).
When you have a collection of similar data elements, it is easier to use an array than to create a separate variable for each of the elements. The array name allows you to associate a single variable name with a list of data elements. Each of the elements in the list is referenced by its name and a subscript (also called an index).
Perl, unlike C-like languages, doesn’t care whether the elements of an array are of the same data type. They can be a mix of numbers and strings. To Perl, an array is a list containing an ordered set of scalars. The name of the array starts with an @ sign and the list is enclosed in parentheses, each element assigned an index value starting at zero (see Figure 5.2).
Figure 5.2 A scalar variable and an array variable.
Assignment.
If the array is initialized, the elements are enclosed in parentheses, and each element is separated by a comma. The list is parenthesized due to the lower precedence of the comma operator over the assignment operator. Elements in an array are simply scalars.
The qw construct can also be used to quote words in a list (similar to qq, q, and qx). The items in the list are treated as singly quoted words and the comma is also provided.
$pal = "John"; # Scalar holds one value @pals = ("John", "Sam", "Nicky", "Jake" ); # Array holds a list of values @pals = qw(John Sam Nicky Jake); # qw means quote word and include comma
Example 5.10
1 @name=("Guy", "Tom", "Dan", "Roy"); 2 @list=(2..10); 3 @grades=(100, 90, 65, 96, 40, 75); 4 @items=($a, $b, $c); 5 @empty=(); 6 $size=@items; 7 @mammals = qw/dogs cats cows/; 8 @fruit = qw(apples pears peaches);
Explanation
- 1. The array @name is initialized with a list of four string literals.
- 2. The array @list is assigned numbers ranging from 2 through 10.
- 3. The array @grades is initialized with a list of six numeric literals.
- 4. The array @items is initialized with the values of three scalar variables.
- 5. The array @empty is assigned an empty list.
- 6. The array @items is assigned to the scalar variable $size. The value of the scalar is the number of elements in the array (in this example, 3).
- 7.
The qw (quote word) construct is followed by a delimiter of your choice and a string. qw() extracts words out of your string using embedded whitespace as the delimiter and returns the words as a list. Variables are not interpolated. Each word in the list is treated as a singly quoted word. The list is terminated with a closing delimiter. This example could be written like so:
@mammals = ('cats', 'dogs', 'cows' );
- 8. The qw construct accepts paired characters ( ), { },<>, and [ ], as optional delimiters.
Output and Input Special Variables ($, and $“).
The $, is a special default global variable, called the output field separator. When used by the print function to print a list or an array (not enclosed in quotes), this variable separates the elements and is initially set to undef. For example, print 1,2,3 would ouput 123. Although you can assign a different value to the $, it’s not a good idea, as once changed, it will affect your whole program. (The join function would provide a better solution.)
Example 5.11
1 use warnings; 2 my @pets=("Smokey", "Fido", "Gills", "Skiddy"); 3 print @pets, "\n"; # Output separator is undef 4 $,="****"; # Changes the output field separator 5 print @pets,"\n"; # no quotes; ***** replaces undef 6 print 1,2,3, "\n"; (Output) SmokeyFidoGillsSKiddy Smokey****Fido****Gills****Skiddy**** 1****2****3****
Explanation
- 3. The array of pets is printed. The value of of $, is used to separate elements of an unquoted list for the print function and is initially set to undef .
- 4. The $, variable is reset to “****”.
- 5. Now, when the print function displays an unquoted list, the list items are separated by that string.
- 6. The comma evaluates to “****” in the print function.
The $” is a special scalar variable, called the list separator, used to separate the elements of a list in an array, and is by default a single space. For example, when you print an array enclosed in double quotes, the value of $” will be preserved, and you will have a space between the elements.
Example 5.12
1 @grocery_list=qw(meat potatoes rice beans spinach milk); 2 print "@grocery_list\n"; # The list separator is a space 3 $" = "---"; # Change the list separator 4 print "@grocery_list\n"; # The list separator has been changed 5 $, = "||"; # change print's separator 6 print @grocery, "\n"; # no quotes (Ouput) 2 meat potatoes rice beans spinach milk 4 meat---potatoes---rice---beans---spinach---milk 5 meat||potatotes||rice||beans||spinach||milk
Explanation
- 2. The $” variable is called the list separator and is initially set to a space. Unless the array is enclosed in double quotes, the space is lost.
- 3. You can change the $” variable by assigning it a string.
- 4. Now you can see when we print the quoted array, the array separator between the elements has been changed.
- 5. Now the print separator is changed to “||”. If the quotes are removed, the print function will display the list with the new separator.
Array Size.
$#arrayname returns the largest index value in the array; that is, the index value of its last element. Since the array indices start at zero, this value is one less than the array size. The $#arrayname variable can also be used to shorten or truncate the size of the array.
To get the size of an array, you can assign it to a scalar or use the built-in scalar function which used with an array, forces scalar context. It returns the size of the array, one value. (This is defined as a unary operator. See perlop for more details.)
Example 5.13
use warnings; 1 my @grades = (90,89,78,100,87); 2 print "The original array is: @grades\n"; 3 print "The number of the last index is $#grades\n"; 4 print "The value of the last element in the array is $grades[$#grades]\n"; 5 print "The size of the array is ", scalar @grades, "\n"; # my $size = @grades; # Get the size of the array 6 @grades=(); print "The array is completely truncated: @grades\n"; (Output) 2 The original array is: 90 89 78 100 87 3 The number of the last index is 4 4 The value of the last element of the array is 87 5 The size of the array is 5 6 The array is completely truncated:
Explanation
- 1. The array @grades is assigned a list of five numbers.
- 2. The $# construct gets the index value of the last element in the array.
- 3. By using $#grades as an index value, the expression would evaluate to $grades[4].
- 4. The built-in scalar function forces the array to be in scalar context and returns the number of elements in the array. You could also assign the array to a scalar variable, as in $size = @grades, to produce the same result as shown in line 6.
- 6. Using an empty list causes the array to be completely truncated to an empty list.
The Range Operator and Array Assignment.
The .. operator, called the range operator, when used in a list context, returns a list of values starting from the left value to the right value, counting by ones.
Example 5.14
use warnings; 1 my @digits=(0 .. 10); 2 my @letters=( 'A' .. 'Z' ); 3 my @alpha=( 'A' .. 'Z', 'a' .. 'z' ); 4 my @n=( -5 .. 20 );
Explanation
- 1. The array @digits is assigned a list of numbers, 0 incremented by 1 until 10 is reached.
- 2. The array @letters is assigned a list of capital letters, A through Z (ASCII values of A through Z).
- 3. The array @alpha is assigned a list of uppercase and lowercase letters.
- 4. The array @n is assigned a list of numbers, -5 through 20.
Accessing Elements
An array is an ordered list of scalars. To reference the individual elements in an array, each element (a scalar) is preceded by a dollar sign. The index starts at 0, followed by positive whole numbers. For example, in the array @colors, the first element in the array is $colors[0], the next element is $colors[1], and so forth. You can also access elements starting at the end of an array with the index value of -1 and continue downward; for example, -2, -3, and so forth.
To assign a list of values to an array:
@colors = qw( green red blue yellow);
To print the whole array, use the @:
print "@colors\n";
To print single elements of the array:
print "$colors[0] $colors[1]\n";
To print more than one element (meaning, a list):
print "@colors[1,3]\n"; # Now the index values are in a list, # requiring the @ rather than the $ sign.
Figure 5.3 Array elements.
Example 5.15
(The Script) use warnings; # Populating an array and printing its values 1 my @names=('John', 'Joe', 'Jake'); # @names=qw/John Joe Jake/; 2 print @names, "\n"; # prints without the separator 3 print "Hi $names[0], $names[1], and $names[2]!\n"; 4 my $number=@names; # The scalar is assigned the number # of elements in the array 5 print "There are $number elements in the \@names array.\n"; 6 print "The last element of the array is $names[$number -1].\n"; 7 print "The last element of the array is $names[$#names].\n"; # Remember, the array index starts at zero! 8 my @fruit = qw(apples pears peaches plums); 9 print "The first element of the \@fruit array is $fruit[0]; the second element is $fruit[1].\n"; 10 print "Starting at the end of the array; @fruit[-1, -3]\n"; (Output) 2 JohnJoeJake 3 Hi John, Joe, and Jake! 5 There are 3 elements in the @names array. 6 The last element of the array is Jake. 7 The last element of the array is Jake. 9 The first element of the @fruit array is apples; the second element is pears. 10 Starting at the end of the array: plums pears
Explanation
- 1. The @names array is initialized with three strings: John, Joe, and Jake.
- 2. The entire array is displayed without a space between the individual elements. The input field separator, a space, is preserved when the array is enclosed in double quotes: “@names”.
- 3. Each element of the array is printed, starting with subscript number zero.
- 4. The scalar variable $number is assigned the array @names. The value assigned is the number of elements in the array @names. You can also use the built-in scalar function to get the size of an array; for example: $size = scalar @names;
- 5. The last element of the array is printed. Since index values start at zero, the number of elements in the array decremented by one evaluates to the number of the last subscript.
- 6. The last element of the array is printed. The $#names value evaluates to the number of the last subscript in the array. This value used as a subscript will retrieve the last element in the @names array.
- 8. The qw construct creates an array of singly quoted words from the string provided to it, using space as the word separator. (You don’t enclose the words in quotes or separate the words with commas.) The qw delimiter is any pair of nonalphanumeric characters.
- 9. The first two elements of the @fruit array are printed.
- 10. With a negative offset as an index value, the elements of the array are selected from the end of the array. The last element ($fruit[-1]) is plums, and the third element from the end ($fruit[-3]) is pears. Note that when both index values are within the same set of brackets, as in @fruit[-1,-3], the reference is to a list, not a scalar; that is why the @ symbol precedes the name of the array, rather than the $.
Looping Through an Array with the foreach Loop.
One of the best ways to traverse the elements of an array is with Perl’s foreach loop. (See Chapter 7, “If Only, Unconditionally, Forever,” for a thorough discussion.)
This control structure steps through each element of a list (enclosed in parentheses) using a scalar variable as a loop variable. The loop variable references, one at a time, each element in the list, and for each element, the block of statements following the list is executed. When all of the list items have been processed, the loop ends. If the loop variable is missing, $_, the default scalar, is used. You can use a named array or create a list within parentheses.
You may also see code where the word for is used instead of foreach. This is because for and foreach are synonyms. In these examples, foreach is used simply to make it clear that we are going through a list, one element at a time; that is, “for each” element in the list.
Example 5.16
(The Script) use warnings; # Array slices 1 my @names=('Tom', 'Dick', 'Harry', 'Pete' ); 2 foreach $pal (@names){ 3 print "$pal\n"; } 4 foreach ("red", "green", "yellow", "blue"){ 5 print "$_ \n"; } (Output) 3 Tom Dick Harry Pete 5 red green Yellow blue
Explanation
- 1. The array @names is assigned a list: ‘Tom’, ‘Dick’, ‘Harry’, ‘Pete’.
- 2. The foreach loop is used to walk through the list, one word at a time.
- 3. The $pal scalar is used as a loop variable, called an iterator; that is, it points to each successive element of the list for each iteration of the loop. If you don’t provide the iterator variable, Perl uses the topic variable $_ instead. For each iteration of the loop, the block of statements enclosed in curly braces is executed.
- 4. In this example, the foreach loop is not given an iterator variable, so Perl uses the $_ variable instead, even though you can’t see it.
- 5. The value of $_ is printed each time through the loop. (This time we have to explicitly use $_ because we have added the \n to the string.)
Array Copy and Slices
When you assign one array to another array, a copy is made. It’s that simple. Unlike many languages, you are not responsible for the type of data the new array will hold or how many elements it will need. Perl handles the memory allocation and the type of data that will be stored in each element of the new array.
A slice accesses several elements of a list, an array, or a hash simultaneously using a list of index values. You can use a slice to copy some elements of an array into another and also assign values to a slice. If the array on the right-hand side of the assignment operator is larger than the array on the left-hand side, the unused values are discarded. If it is smaller, the values assigned are undefined. As indicated in the following example, the array indices in the slice do not have to be consecutively numbered; each element is assigned the corresponding value from the array on the right-hand side of the assignment operator.
Example 5.17
(The Script) use warnings; # Array copy and slice 1 my @names=('Tom', 'Dick', 'Harry', 'Pete' ); 2 @newnames = @names; # Array copy 3 print "@newnames\n"; 4 @pal=@names[1,2,3]; # Array slice -- @names[1..3] also okay 5 print "@pal\n\n"; 6 ($friend[0,1,2])=@names; # Assign to an array slice 7 print "@friend\n"; (Output) 3 Tom Dick Harry Pete 5 Dick Harry Pete 7 Tom Dick Harry
Explanation
- 1. The array @names is assigned the elements ‘Tom’, ‘Dick’, ‘Harry’, and ‘Pete’.
- 4. The array @pal is assigned the elements 1, 2, and 3 of the @names array. The elements of the @names array are selected and copied in the @pal array.
- 6. The @friend array is created by copying all the values from the @names array and assigning them to @friend elements 0, 1, and 2.
Multidimensional Arrays—Lists of Lists.
Multidimensional arrays are sometimes called tables or matrices. They consist of rows and columns and can be represented with multiple subscripts. In a two-dimensional array, the first subscript represents the row, and the second subscript represents the column.
Perl allows this type of array, but it requires an understanding of references. We will cover this in detail in Chapter 12, “Does This Job Require a Reference?”
5.2.3 Hashes—Unordered Lists
A hash (in some languages called an associative array, map, table, or dictionary) is a variable consisting of one or more pairs of scalars—either strings or numbers. Hashes are often used to create tables, complex data structures, find duplicate entries in a file or array, or to create Perl objects. We will cover objects in detail in Chapter 14, “Bless Those Things! (Object-Oriented Perl).”
Hashes are defined as an unordered list of key/value pairs, similar to a table where the keys are on the left-hand side and the values associated with those keys are on the right-hand side. The name of the hash is preceded by the % and the keys and values are separated by a =>, called the fat comma or digraph operator.
Whereas arrays are ordered lists with numeric indices starting at 0, hashes are unordered lists with string indices, called keys, stored randomly. (When you print out the hash, don’t expect to see the output ordered just as you typed it!)
To summarize, the keys in a hash must be unique. The keys need not be quoted unless they begin with a number or contain hyphens, spaces, or special characters. Since the keys are really just strings, to be safe, quoting the keys (either single or double quotes) can prevent unwanted side effects. It’s up to you. The values associated with the key can be much more complex that what we are showing here, and require an understanding of Perl references. These complex types are discussed in Chapter 12, “Does This Job Require a Reference?”
my %pet = ("Name" => "Sneaky", "Type" => "cat", "Owner" => "Carol", "Color" => "yellow", );
So for this example, the keys and values for the hash called %pet, are as follows:
Keys |
Values |
“Name” |
“Sneaky” |
“Type” |
“cat” |
“Owner” |
“Carol” |
“Color” |
“yellow” |
Assignment.
As in scalars and arrays, a hash variable must be defined before its elements can be referenced. Since a hash consists of pairs of values, indexed by the first element of each pair, if one of the elements in a pair is missing, the association of the keys and their respective values will be affected. When assigning keys and values, make sure you have a key associated with its corresponding value. When indexing a hash, curly braces are used instead of square brackets.
Example 5.18
1 my %seasons=("Sp" => "Spring", "Su" => "Summer", "F" => "Fall", "W" => "Winter", ); 2 my %days=("Mon" => "Monday", "Tue" => "Tuesday", "Wed" => undef, ); 3 $days{"Wed"}="Wednesday";
Explanation
- 1. The hash %seasons is assigned keys and values. Each key and value is separated by the fat comma, =>. The string “Sp” is the key with a corresponding value of “Spring”, the string “Su” is the key for its corresponding value “Summer”, and so on. It is not necessary to quote the key if it is a single word and does not begin with a number or contain spaces.
- 2. The hash %days is assigned keys and values. The third key, “Wed”, is assigned undef. The undef function evaluates to an undefined value; in this example, it serves as a placeholder with an empty value to be filled in later.
- 3. Individual elements of a hash are scalars. The key “Wed” is assigned the string value “Wednesday”. The index is enclosed in curly braces. Note: the keys do not have any consecutive numbering order and the pairs can consist of numbers and/or strings.
Accessing Hash Values
When accessing the values of a hash, the subscript or index consists of the key enclosed in curly braces. Perl provides a set of functions to list the keys, values, and each of the elements of the hash.
Due to the internal hashing techniques used to store the keys, Perl does not guarantee the order in which an entire hash is printed.
Example 5.19
(The Script) use warnings; # Assigning keys and values to a hash my(%department,$department,$school); # Declare variables 1 %department = ( 2 "Eng" => "Engineering", # keys do not require quotes "M" => "Math", "S" => "Science", "CS" => "Computer Science", "Ed" => "Education", 3 ); 4 $department = $department{'M'}; # Either single, double quotes 5 $school = $department{'Ed'}; 6 print "I work in the $department section\n" ; 7 print "Funds in the $school department are being cut.\n"; 8 print qq/I'm currently enrolled in a $department{'CS'} course.\n/; 9 print qq/The department hash looks like this:\n/; 10 print %department, "\n"; # The printout is not in the expected # order due to internal hashing (Output) 6 I work in the Math section 7 Funds in the Education department are being cut. 8 I'm currently enrolled in a Computer Science course. 9 The department hash looks like this: 10 SScienceCSComputer ScienceEdEducationMMathEngEngineering
Explanation
- 1. The hash is called %department. It is assigned keys and values.
- 2. The first key is the string Eng, and the value associated with it is Engineering.
- 3. The closing parenthesis and semicolon end the assignment.
- 4. The scalar $department is assigned Math, the value associated with the M key. It’s sometimes confusing to name different types of variables by the same name. In this example, it might be better to change $department to $subject or $course, for example.
- 5. The scalar $school is assigned Education, the value associated with the Ed key.
- 6. The quoted string is printed; the scalar $department is interpolated.
- 7. The quoted string is printed; the scalar $school is interpolated.
- 8. The quoted string and the value associated with the CS key are printed.
- 9, 10. The entire hash is printed, with keys and values packed together and not in any specific order. A key and its value, however, will always remain paired.
Hash Slices
A hash slice is a list of hash keys. The hash name is preceded by the @ symbol and assigned a list of hash keys enclosed in curly braces. The hash slice lets you access one or more hash elements in one statement, rather than by going through a loop.
Example 5.20
(The Script) use warnings; # Hash slices 1 my %officer= ("name" => "Tom Savage", "rank" => "Colonel", "dob" => "05/19/66" ); 2 my @info=@officer{"name","rank","dob"}; # Hash slice 3 print "@info\n"; 4 @officer{'phone','base'}=('730-123-4455','Camp Lejeune'); 5 print %officer, "\n"; (Output) 2 Tom Savage Colonel 05/19/66 6 baseCamp Lejeunedob05/19/66nameTom Savagephone730-123-4455rankColonel
Explanation
- 1. The hash %officer is assigned keys and values.
- 2. This is an example of a hash slice. The list of hash keys, “name”,“rank”, and “dob” are assigned to the @info array. The name of the hash is prepended with an @ because this is a list of keys. The values corresponding to the list of keys are assigned to @info.
- 3. The keys and their corresponding values are printed. Using the slice is sometimes easier than using a loop to do the same thing.
- 4. Now using a slice in the assignment, we can create two new entries in the hash.
Removing Duplicates from a List Using a Hash
Because all keys in a hash must be unique, one way to remove duplicates from a list, whether an array or file, is to list items as keys in a hash. The values can be used to keep track of the number of duplicates or simply left undefined. The keys of the new hash will contain no duplicates. See the section, “The map Function,” later in this chapter, for more examples.
Example 5.21
(The Script) use warnings; 1 my %dup=(); # Create an empty hash. 2 my @colors=qw(red blue red green yellow green red orange); 3 foreach my $color (@colors){ $dup{$color} = $dup{$color}++; # Adds one to the value side of # the hash. May be written # $dup{$color}=$dup{$color}+1 } printf"Color Number of Occurrences\n"; 4 while((my $key, my $value)=each %dup){ printf"%-12s%-s\n",$key, $value; } 5 @colors = sort keys %dup; print "Duplicates removed: @colors\n"; (Output) perl dup.plx Color Number of Occurrences 3 green 2 blue 1 orange 1 red 3 yellow 1 5 Duplicates removed: blue green orange red yellow
Explanation
- This is the declaration for an empty hash called %dup().
The array of colors contains a number of duplicate entries, as shown in Figure 5.4.
Figure 5.4 Removing duplicates with a hash.
- For each item in the array of colors, a key and value are assigned to the %dup hash. The first time the color is seen, it is created as a key in the hash; its value is incremented by 1, starting at 0 (that is, the key is the color and the value is the number of times the color occurs). Because the key must be unique, if a second color occurs and is a duplicate, the first occurrence will be overwritten by the duplicate and the value associated with it will increase by one.
- The built-in each function is used as an expression in the while loop. It will retrieve and assign each key and each value from the hash to $key and $value respectively, and a pair is printed each time through the loop.
- The keys of %dup hash are a unique list of colors. They are sorted and assigned to the @colors array.
5.2.4 Complex Data Structures
By combining arrays and hashes, you can make more complex data structures, such as arrays of hashes, hashes with nested hashes, arrays of arrays, and so on. Here is an example of an array of arrays requiring references.
my $matrix = [ [ 0, 2, 4 ], [ 4, 1, 32 ], [ 12, 15, 17 ] ] ;
To create these structures, you should have an understanding of how Perl references and complex data structures are used. (See Chapter 12, “Does This Job Require a Reference?”)