| Picking Up Perl:A Tutorial Book for New Perl Programmers source ref: perl.html |
|
Chapter-3
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.
|
|
|