Now that we have a good understanding of the way scalar data and variables work and what can be done with them in Perl, we will look into the most basic of Perl's natural data structures--arrays.
The arrays in Perl are semantically closest to lists in Lisp or Scheme (sans cons cells), however the syntax that is used to access arrays is closer to arrays in C. In fact, one can often treat Perl's arrays as if they were simply C arrays, but they are actually much more powerful than that.
Perl arrays grow and shrink dynamically as needed. The more data you put into a Perl list, the bigger it gets. As you remove elements from the list, the list will shrink to the right size. Note that this is inherently different from arrays in the C language, where the programmer must keep track and control the size of the array.
However, Perl arrays are accessible just like C arrays. So, you can subscript to anywhere within a given list at will. There is no need to process through the first four elements of the list to get the fifth element (as in Scheme). In this manner, you get the advantages of both a dynamic list, and a static-size array.
The only penalty that you pay for this flexibility is that when an array is growing very large very quickly, it can be a bit inefficient. However, when this must occur, Perl allows you to pre-build an array of certain size. We will show how to do this a bit later.
A Perl array is always a list of scalars. Of course, since Perl makes no direct distinction between numeric and string values, you can easily mix different types of scalars within the same array. However, everything in the array must be a scalar(8).
Note the difference in terminology that is used here. Arrays refer to variables that store a list of scalar values. Lists can be written as literals (see section List Literals) and used in a variety of ways. One of the ways that list literals can be used is to assign to array variables (see section Array Variables). We will discuss both list literals and array variables in this chapter.
Like scalars, it is possible to write lists as literals right in your code. Of course, as with inserting string literals in your code, you must use proper quoting.
There are two primary ways to quote list literals that we will discuss
here. One is using ()
, and the other is using what is called a
quoting operator. The quoting operator for lists is qw
. A
quoting operator is always followed by a single character, which is the
"stop character". It will eat up all the following input until the
next "stop character". In the case of qw
, it will use each
token that it finds as an element in a list until the second "stop
character" is reached. The advantage of the qw
operator is that
you do not need to quote strings in any additional way, since qw
is already doing the quoting for you.
Here are a few examples of some list literals, using both ()
and
the qw
operator.
(); # this list has no elements; the empty list qw//; # another empty list ("a", "b", "c", 1, 2, 3); # a list with six elements qw/hello world how are you today/; # another list with six elements
Note that when we use the ()
, we have to quote all strings, and we
need to separate everything by commas. The qw
operator does not
require this.
Finally, if you have any two scalar values where all the values between
them can be enumerated, you can use an operator called the ..
operator to build a list. This is most easily seen in an example:
(1 .. 100); # a list of 100 elements: the numbers from 1 to 100 ('A' .. 'Z'); # a list of 26 elements: the uppercase letters From A to Z ('01' .. '31'); # a list of 31 elements: all possible days of a month # with leading zeros on the single digit days
You will find the ..
operator particularly useful with slices, which
we will talk about later in this chapter.
As with scalars, what good are literals if you cannot have variables? So, Perl provides a way to make array variables.
Each variable in Perl starts with a special character that identifies what type of variable it is. We saw that scalar variables always start with a `$'. Similarly, all array variables start with the character, `@', under the same naming rules that are used for scalar variables.
Of course, we cannot do much with a variable if we cannot assign things to it, so the assignment operator works as perfectly with arrays as it did with scalars. We must be sure, though, to always make the right hand side of the assignment a list, not a scalar! Here are a few examples:
use strict; my @stuff = qw/a b c/; # @stuff a three element list my @things = (1, 2, 3, 4); # @things is a four element list my $oneThing = "all alone"; my @allOfIt = (@stuff, $oneThing, @things); # @allOfIt has 8 elements!
Note the cute thing we can do with the ()
when assigning
@allOfIt
. When using ()
, Perl allows us to insert other
variables in the list. These variables can be either scalar or array
variables! So, you can quickly build up a new list by "concatenating"
other lists and scalar variables together. Then, that new list can be
assigned to a new array, or used in any other way that list literals can
be used.
Every time an array variable is declared, a special set of scalar variables automatically springs into existence, and those scalars change along with changes in the array with which they are associated.
First of all, for an array, @array
, of n elements. There
are scalar variables $array[0]
, $array[1]
, ...,
$array[n-1]
that contain first, second, third, ...,
nth elements in the array, respectively. The variables in this
format are full-fledged scalar variables. This means that anything you
can do with a scalar variable, you can do with these elements. This
provides a way to access array elements by subscript. In addition, it
provides a way to change, modify and update individual elements without
actually using the @array
variable.
Another scalar variable that is associated to any array variable,
@array
, is $#array
. This variable always contains the
subscript of the last element in the array. In other words,
$array[$#array]
is always the last element of the array. The
length of the array is always $#array + 1
. Again, you are
permitted to do anything with this variable that you can normally do
with any other scalar variable; however, you must always make sure to
leave the value as an integer greater than or equal to -1. In fact, if
you know an array is going to grow very large quickly, you probably want
to set this variable to a very high value. When you change the value of
$#array
, you not only resize the array for your use, you also
direct Perl to allocate a specific amount of space for @array
.
Here are a few examples that use the associated scalar variables for an array:
use strict; my @someStuff = qw/Hello and welcome/; # @someStuff: an array of 3 elements $#someStuff = 0; # @someStuff now is simply ("Hello") $someStuff[1] = "Joe"; # Now @someStuff is ("Hello", "Joe") $#someStuff = -1; # @someStuff is now empty @someStuff = (); # does same thing as previous line
Clearly, arrays and lists are very useful. However, there are a few more things in Perl you can use to make arrays and lists even more useful.
Sometimes, you may want to create a new array based on some subset of elements from another array. To do this, you use a slice. Slices use a subscript that is itself a list of integers to grab a list of elements from an array. This looks easier in Perl than it does in English:
use strict; my @stuff = qw/everybody wants a rock/; my @rock = @stuff[1 .. $#stuff]; # @rock is qw/wants a rock/ my @want = @stuff[ 0 .. 1]; # @want is qw/everybody wants/ @rock = @stuff[0, $#stuff]; # @rock is qw/everybody rock/
As you can see, you can use both the ..
operator and commas to
build a list for use as a slice subscript. This can be a very useful
feature for array manipulation.
Perl also provides quite a few functions that operate on arrays. As you learn more and more Perl, you will see lots of interesting functions that work with arrays.
Now, we'll discuss a few of these functions that work on arrays: @builtin{push}, @builtin{pop}, @builtin{shift}, and @builtin{unshift}.
The names @builtin{shift} and @builtin{unshift} are an artifact of the Unix shells that used them to "shift around" incoming arguments.
What more is a stack than an unbounded array of things? This attitude
is seen in Perl through the push
and pop
functions. These
functions treat the "right hand side" (i.e., the end) of the array as
the top of the stack. Here is an example:
use strict; my @stack; push(@stack, 7, 6, "go"); # @stack is now qw/7 6 go/ my $action = pop @stack; # $action is "go", @stack is (7, 6) my $value = pop(@stack) + pop(@stack); # value is 6 + 7 = 13, @stack is empty
If we can do stacks, then why not queues? You can build a queue in Perl
by using the unshift
and pop
functions
together.(9) Think of the unshift
function as "enqueue" and the
pop
function as "dequeue". Here is an example:
use strict; my @queue; unshift (@queue, "Customer 1"); # @queue is now ("Customer 1") unshift (@queue, "Customer 2"); # @queue is now ("Customer 2" "Customer 1") unshift (@queue, "Customer 3"); # @queue is now ("Customer 3" "Customer 2" "Customer 1") my $item = pop(@queue); # @queue is now ("Customer 3" "Customer 2") print "Servicing $item\n"; # prints: Servicing Customer 1\n $item = pop(@queue); # @queue is now ("Customer 3") print "Servicing $item\n"; # prints: Servicing Customer 2\n
This queue example works because unshift
places items onto the
front of the array, and pop
takes items from the end of the
array. However, be careful using more than two arguments on the
unshift
when you want to process an array as a queue. Recall
that unshift
places its arguments onto the array in order
as they are listed in the function call. Consider this example:
use strict; my @notAqueue; unshift(@notAqueue, "Customer 0", "Customer 1"); # @queue is now ("Customer 0", "Customer 1") unshift (@notAqueue, "Customer 2"); # @queue is now ("Customer 2", "Customer 0", "Customer 1")
Notice that this variable, @notAqueue
, is not really a queue, if
we use pop
to remove items. The moral here is to be careful when
using unshift
in this manner, since it places it arguments on the
array in order.
It may have occurred to you by now that in certain places we can use a list, and in other places we can use a scalar. Perl knows this as well, and decides which is permitted by something called a context.
The context can be either list context or scalar context. Many operations do different things depending on what the current context is.
For example, it is actually valid to use an array variable, such as
@array
, in a scalar context. When you do this, the array variable
evaluates to the number of elements in the array. Consider this example:
use strict; my @things = qw/a few of my favorite/; my $count = @things; # $count is 5 my @moreThings = @things; # @moreThings is same as @things
Note that Perl knows not to try and stuff @things
into a scalar,
which does not make any sense. It evaluates @things
in a scalar
context and given the number of elements in the array.
You must always be aware of the context of your operations. Assuming the wrong context can cause a plethora of problems for the new Perl programmer.
Array variables can also be evaluated through interpolation into a double-quoted string. This works very much like the interpolation of scalars into double-quoted strings (see section Scalar Interpolation). When an array variable is encountered in a double-quoted string, Perl will join the array together, separating each element by spaces. Here is an example:
use strict; my @saying = qw/these are a few of my favorite/; my $statement = "@saying things.\n"; # $statement is "these are a few of my favorite things.\n" my $stuff = "@saying[0 .. 1] @saying[$#saying - 1, $#saying] things.\n" # $stuff is "these are my favorite things.\n"
Note the use of slices when assigning $stuff
. As you can see,
Perl can be very expressive when we begin to use the interaction of
different, interesting features.
Go to the first, previous, next, last section, table of contents.