- Putting Things into Lists and Arrays
- Getting Elements Out of an Array
- Manipulating Arrays
- Exercise: Playing a Little Game
- Summary
- Q&A
- Workshop
Getting Elements Out of an Array
So far in this hour, you've been slinging around whole arrays and lists and putting information into arrays. How can you get that information back out?
One way to get the contents of the entire array is to put the array variable in double quotation marks:
print "@array";
An array in double quotes is interpolated, and its elements are returned separated by spaces. This example prints the elements of @array with a space separating each element.
Many times, though, you need to get to individual elements of arrays. You may need to search for an element, change the value of an element, or to add or remove individual elements in an array.
Individual elements in an array are accessed by a numeric index. The index for array elements starts at the number 0 and increases by 1 for each additional element. Each element of the array has an index value, as shown in the following figure.
The number of elements in an array is limited only by your system's memory. To access an element, you use the syntax
$array[index]
where array is the array name and index is the index of the element you want (also called a subscript). The array doesn't have to exist before you refer to individual elements; if it does not already exist, it just automagically springs into existence. Some examples of accessing array elements follow:
@trees=qw(oak cedar maple apple); print $trees[0]; # Prints "oak" print $trees[3]; # Prints "apple". $trees[4]='pine';
Notice that to talk about an individual element of @trees, the code uses a $. "I thought the $ marker was usually reserved for scalars; what's going on?" you might ask. The answer is that the $ in $trees[3] does refer to a scalar: one scalar value within @trees. (Scalars are also indicated by a dollar sign because they're singular as well. You should notice a pattern here.)
At the beginning of this hour, you discovered that scalars and arrays can have the same variable names and remain unrelated. Perl can tell the difference between $trees, a scalar variable that has nothing to do with the @trees array, and $trees[0], the first element in the @trees array, because of the square brackets in $trees[0]. Perl knows that you're taking about the first element of @trees and not talking about $trees at all.
You can also talk about a subgroup within an array, called a slice. To take a slice of an array, you use both the @ type identifierto indicate that you're talking about a group of thingsand square bracketsto indicate you're talking about individual elements of an array, as shown here:
@trees=qw(oak cedar maple apple cherry pine peach fir); @trees[3,4,6]; # Just the fruit trees @conifers=@trees[5,7]; # Just the conifers
Finding the End of an Array
Sometimes you need to find the end of the arrayfor example, to see how many trees are in the @trees array or to cut some trees out of the @trees array. Perl provides a couple of mechanisms for finding the end. The first is a special variable in the form $#arrayname. It returns the number of the last valid index of the array. Check out this example:
@trees=qw(oak cedar maple apple cherry pine peach fir); print $#trees;
This example contains eight elements, but you must remember that arrays are numbered starting at 0. So the preceding example prints the number 7. Modifying the value of $#trees changes the length of the array. Making it smaller truncates the array at whatever index you specify, and making it larger gives the array more elements. The newly added elements all have their values set to undef.
The other method of finding the size of an array is to use the array variable in a place where a scalar is expected:
$size=@array;
This puts the number of elements in @array into $size. This takes advantage of a Perl concept called context, explained in the next section.
NOTE
You can also specify negative indexes for arrays. Negative index numbers start counting from the end of the array and work backward. For example, $array[-1] is the last element of @array, $array[-2] is the next to the last element, and so on.
Learning More about Context
What is context? Context means the things that surround an item of interest to help define what that item means. For example, seeing a man in surgical scrubs can have different meanings depending on where he is: In a hospital, the fact that the man is wearing scrubs might mean that he's a doctor; at a Halloween party, he could be just another party guest in costume.
Human language uses context to help determine the meaning of words. For example, the word level can have several different meanings depending on how it's used and what context it's in:
The carpenter used a level to hang the door straight.
The moderator spoke in a level tone.
The water in the pool was at waist level.
It's the same word each time, but the meaning has changed. It becomes a noun, an adjective, and a different kind of noun depending on how it's used in a sentence.
Perl is also sensitive to context. Functions and operators in Perl can behave differently depending on what context they're used in. The two most important contexts in Perl are list context and scalar context.
As you've seen, you can use one operatorthe equals signto perform assignment with both arrays and scalars. The type of expression (list or scalar) on the left side of the assignment operator determines what context the things on the right side are evaluated in, as shown in the following lines of code:
$a=$b; # Scalar on the left: this is scalar context. @foo=@bar; # Array on the left: this is list context. ($a)=@foo; # List on the left: this is also list context. $b=@bar; # Scalar on the left: this is scalar context.
The last line is interesting, because it puts an array into scalar context. As was stated in the previous section, evaluating an array in a scalar context returns the number of elements in the array.
More about the Size and End of an Array
Observe $a and $b in the following few lines of code; they do almost the same thing:
@foo=qw( water cola juice lemonade ); $a=@foo; $b=$#foo; print "$a\n"; print "$b\n";
At the end of this code, $a contains the number 4, and $b contains the number 3. Why the difference? $a is @foo evaluated in a scalar context, and it contains the number of elements. $b, on the other hand, is set to the index of the last element, and indexes start counting at 0.
Because arrays in a scalar context return the number of elements in the array, testing whether an array contains elements becomes this simple:
@mydata=qw( oats peas beans barley ); if (@mydata) { print "The array has elements!\n"; }
Here, the array @mydata is evaluated as a scalar, and it returns the number of elementsin this case, 4. The number 4 evaluates to true in an if statement, and the body of the if block is run.
NOTE
Actually, @mydata here is used in a special kind of scalar context called a Boolean context, but it behaves the same way. Boolean context occurs when Perl expects a true or false value, such as in an if statement's test expression. One other context, called void context, will be explained in Hour 9, "More Functions and Operators."
Context with Operators and Functions
Many of Perl's operators and functions force their arguments to be either scalar context or list context. Sometimes the operators or functions behave differently depending on what context they're in. Some functions you've already encountered have these properties; however, this fact hasn't been important until now, because they have only had scalars to work on.
The print function expects a list as an argument. It doesn't particularly matter what context the list is evaluated in, though. So printing an array with print like this causes the array to be evaluated in a list context, yielding the elements of @foo:
print @foo;
You can use a special pseudofunction called scalar to force something into a scalar context:
print scalar(@foo);
This example prints the number of elements in @foo. The scalar function forces @foo to be evaluated in a scalar context, so @foo returns the number of elements in @foo. Then the print function simply prints the number returned.
The chomp function you learned about in Hour 2, "Perl's Building Blocks: Numbers and Strings," takes either an array or a scalar as an argument. If chomp is presented with a scalar, it removes the record separator from the end of the scalar. If it is presented with an array, it removes the record separator from the end of each scalar in the array.
Also in Hour 2 you learned how to read a line of input from the keyboard by using <STDIN>. The angle brackets (<>) are really an operator in Perl, and they behave differently depending on context. In a scalar context, this operator reads one line of input from the terminal. In a list context, however, it reads all the input from the terminaluntil the End of File is readand places the data in the list. Examine the following:
$a=<STDIN>; # Scalar context, reads one line into $a. @whole=<STDIN>; # List context, reads all input into the array @whole. ($a)=<STDIN>; # List context, reads all input into the assignable list.
In the third example, what does $a receive? Remember from earlier in this hour that if the left side in a list assignment doesn't have enough variables to hold all the right-side elements, the extra right-side elements are dropped. So here all input from the terminal is read, but $a receives only the first line.
NOTE
What's an End of File? When Perl reads all input from a terminal, you need to signal when you're done feeding Perl data. You usually do so typing an end-of-file (EOF) character. That character differs depending on your operating system. Under Unix, that character is usually a Ctrl+D at the beginning of a line. On MS-DOS or Windows systems, that character is Ctrl+Z two times anywhere in the input.
Also in Hour 2 you learned about the repetition operator x. The repetition operator has a special behavior in list context. If the left operand is in parenthesis, and the operator itself is used in a list context, it returns a list of the left operand repeated. The following example builds an array of 100 stars:
@stars= ("*") x 100;
The left operand of x"*"is in parentheses, and assigning it to an array puts it in a list context. This syntax is useful for initializing an array's elements to a particular value.
Another operator that you've been usingand probably didn't know it was an operatoris the comma (,). Until now, you've been using the comma to separate elements of literal lists, like this:
@pets=('cat', 'dog', 'fish', 'canary', 'iguana');
The preceding snippet has the list being evaluated in a list context, as normal. In a scalar context, on the other hand, the comma is an operator that evaluates each element from left to right and returns the value of the rightmost element:
$last_pet=('cat', 'dog', 'fish', 'canary', 'iguana'); # Not what you think!
In this snippet, the pets named on the right side of the assignment operator aren't really a list, despite the parentheses around them. The right side of the expression is evaluated in a scalar context because of the scalar $last_pet on the left of the equals sign, so the group of string literals is evaluated as a scalar. The result is that $last_pet is set equal to 'iguana'.
Another example of a function that acts in two completely different ways depending on which context it's in is the localtime function. In a scalar context, the localtime function returns a nicely formatted string with the current time. For example, print scalar(localtime); would print something like: Thu Sep 16 23:00:06 1999. In a list context, localtime returns an list of elements that describe the current time:
($sec, $min, $hour, $mday, $mon, $year_off, $wday, $yday, $isdst)=localtime;
What these values represent is shown in Table 4.1.
Table 4.1 Return Values from localtime, in List Context
Field |
Value |
$sec |
Seconds, 059 |
$min |
Minutes, 059 |
$hour |
Hour, 023 |
$mday |
Day of the month, 128, 29, 30, or 31 |
$mon |
Month of the year, 011 (be careful here!) |
$year_off |
-Number of years since 1900 (add 1900 to this number for the correct 4-digit year) |
$wday |
Day of the week, 06 |
$yday |
Day of the year, 0364 or 365 |
$isdst |
True if Daylight Savings Time is in effect |
NOTE
Do not attempt to get a four-digit year by concatenating '19' in front of the year returned by localtime. The year returned is an offset from 1900in 1999, year is '99'; in 2001 it is '101'. Adding 1900 to this value will work correctly well beyond year 2000. Perl has no Y2K bugs, but simply concatenating '19' (or '20') with the year will cause a Y2K problem in your programs.
How do you know what context a function or operator forces on its arguments and how it's going to function depending on whether it's in a scalar context or a list context? Quite simply, you don't, and there's really no good way to guess. The online documentation lists each function and operator and explains these factors for each one if you're unsure. For the remainder of this book, if a function or operand forces a context on its arguments, or behaves differently depending on what context it's evaluated in, I will indicate all these points when the function is first presented. It doesn't happen often, but when it does, I'll be sure to tell you.