Go to the first, previous, next, last section, table of contents.


Arrays

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 Semantics of 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.

List Literals

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.

Array Variables

As with scalars, what good are literals if you cannot have variables? So, Perl provides a way to make array variables.

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.

Associated Scalars

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

Manipulating Arrays and Lists

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.

It Slices!

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.

Functions

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.

Arrays as Stacks

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

Arrays as Queues

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.

The Context--List vs. Scalar

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 Interpolation

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.