ЭЛЕКТРОННАЯ БИБЛИОТЕКА КОАПП
Сборники Художественной, Технической, Справочной, Английской, Нормативной, Исторической, и др. литературы.



3.4 Array Operators and Functions

Array functions and operators act on entire arrays. Some return a list, which can then either be used as a value for another array function, or assigned into an array variable.

3.4.1 Assignment

Probably the most important array operator is the array assignment operator, which gives an array variable a value. It is an equal sign, just like the scalar assignment operator. Perl determines whether the assignment is a scalar assignment or an array assignment by noticing whether the assignment is to a scalar or an array variable.[1] For example:

[1] This applies to scalar or array "lvalues" as well as to simple variables.

@fred = (1,2,3); # The fred array gets a three-element literal
@barney = @fred; # now that is copied to @barney

If you assign a scalar value to an array variable, the scalar value becomes the single element of an array:

@huh = 1; # 1 is promoted to the list (1) automatically
          # that is, @huh now is (1)

An array variable name may appear in a list-literal list. When the value of the list is computed, Perl replaces the array variable name with the current values of the array, like so:

@fred = qw(one two);
@barney = (4,5,@fred,6,7);  # @barney becomes 
                            # (4,5,"one","two",6,7)
@barney = (8,@barney);      # puts 8 in front of @barney
@barney = (@barney,"last"); # and a "last" at the end
# @barney is now (8,4,5,"one","two",6,7,"last")

Note that the inserted array elements are at the same level as the rest of the literals: a list cannot contain another list as an element.[2]

[2] Although a list reference is permitted as a list element, it's not really a list as a list element. Still, it works out to nearly the same thing, allowing for multidimensional arrays. See Chapter 4 of Programming Perl or perllol for more details.

If a list literal contains only variable references (not expressions), you can treat the list literal as a variable. In other words, you can use it on the left side of an assignment. Each scalar variable in the list literal takes on the corresponding value from the list on the right side of the assignment. For example:

($a,$b,$c) = (1,2,3);     # give 1 to $a, 2 to $b, 3 to $c
($a,$b) = ($b,$a);        # swap $a and $b
($d,@fred) = ($a,$b,$c);  # give $a to $d, and ($b,$c) to @fred
($e,@fred) = @fred;       # remove the first element of @fred to $e
                          # this makes @fred = ($c) and $e = $b

If the number of elements you assign does not match the number of variables to hold the values, any excess values (on the right side of the equal sign) are silently discarded, and any excess variables (on the left side of the equal sign) are given the value of undef.

An array variable appearing in the array literal list must be last, because the array variable is "greedy" and consumes all remaining values. (Well, you could put other variables after it, but they would just get undef values.)

If you assign an array variable to a scalar variable, the number assigned is the length of the array, as in:

@fred = (4,5,6); # initialize @fred
$a = @fred;      # $a gets 3, the current length of @fred

The length is also returned whenever you use an array variable name where a scalar value is needed. (In the section "Scalar and List Context" later in this chapter, we'll see that this method is called using the array name in a scalar context.) For example, to get one less than the length of the array, you can use @fred-1, because the scalar subtraction operator wants scalars for both of its operands. Notice the following:

$a = @fred;   # $a gets the length of @fred
($a) = @fred; # $a gets the first element of @fred

The first assignment is a scalar assignment, and so @fred is treated as a scalar, yielding its length. The second assignment is an array assignment (even if only one value is wanted), and thus yields the first element of @fred, silently discarding all the rest.

The value of an array assignment is itself a list value, and can be cascaded as with scalar assignments. For example:

@fred = (@barney = (2,3,4)); # @fred and @barney get (2,3,4)
@fred = @barney = (2,3,4);   # same thing

3.4.2 Array Element Access

So far, we've been treating the array as a whole, adding and removing values by doing array assignments. Many useful programs are constructed using arrays without ever accessing any specific array element. However, Perl provides a traditional subscripting operator to access an array element by numeric index.

For the subscripting operator, the array elements are numbered using sequential integers, beginning at 0,[3] and increasing by 1 for each element. The first element of the @fred array is accessed as $fred[0]. Note that the @ on the array name becomes a $ on the element reference. This is because accessing an element of the array identifies a scalar variable (part of the array), which can either be assigned to or have its current value used in an expression, like so:

[3] You can change the index value of the first element to something else (like 1). However, doing so has drastic effects, will probably confuse people maintaining your code, and might break the routines you take from other people. Thus, we highly recommend that you consider this feature unusable.

@fred = (7,8,9);
$b = $fred[0]; # give 7 to $b (first element of @fred)
$fred[0] = 5;  # now @fred = (5,8,9)

Other elements can be accessed with equal ease, as in:

$c = $fred[1];                  # give 8 to $c
$fred[2]++;                     # increment the third element of @fred
$fred[1] += 4;                  # add 4 to the second element
($fred[0],$fred[1]) = ($fred[1],$fred[0]); # swap the first two

Accessing a list of elements from the same array (as in the previous example) is called a slice, and occurs often enough so that a special representation exists for it:

@fred[0,1]                     # same as ($fred[0],$fred[1])
@fred[0,1] = @fred[1,0]        # swap the first two elements
@fred[0,1,2] = @fred[1,1,1]    # make all 3 elements like the 2nd
@fred[1,2] = (9,10);           # change the last two values to 9 and 10

Note that this slice uses an @ prefix rather than a $. This is because you are creating an array variable by selecting part of the array rather than a scalar variable accessing just one element.

Slices also work on literal lists, or any function that returns a list value:

@who = (qw(fred barney betty wilma))[2,3];
# like @x = qw(fred barney betty wilma); @who = @x[2,3];

The index values in these examples have been literal integers, but the index can also be any expression that returns a number, which is then used to select the appropriate element:

@fred = (7,8,9);
$a = 2;
$b = $fred[$a];       # like $fred[2], or the value of 9
$c = $fred[$a-1];     # $c gets $fred[1], or 8
($c) = (7,8,9)[$a-1]; # same thing using slice

Perl programs can thus have array accesses similar to many traditional programming languages.

This idea of using an expression for the subscript also works for slices. Remember, however, that the subscript for a slice is a list of values, so the expression is an array expression, rather than a scalar expression. For example:

@fred = (7,8,9); # as in previous example
@barney = (2,1,0);
@backfred = @fred[@barney];
# same as @fred[2,1,0], or ($fred[2],$fred[1],$fred[0]), or
# (9,8,7)

If you access an array element beyond the ends of the current array (that is, an index of less than 0 or greater than the last element's index), the undef value is returned without warning. For example:

@fred = (1,2,3);
$barney = $fred[7]; # $barney is now undef

Assigning a value beyond the end of the current array automatically extends the array (giving a value of undef to all intermediate values, if any). For example:

@fred = (1,2,3);
$fred[3] = "hi"; # @fred is now (1,2,3,"hi")
$fred[6] = "ho"; # @fred is now (1,2,3,"hi",undef,undef,"ho")

Assignment to an array element with a subscript of less than 0 is a fatal error, because it is probably the result of Very Bad Programming Style.

You can use $#fred to get the index value of the last element of @fred. You can even assign to this value to change the apparent length of @fred, making it grow or shrink, but such an assignment is generally unnecessary, because the array grows and shrinks automatically.

A negative subscript on an array counts back from the end. So, another way to get at the last element is with the subscript -1. The second to the last element would be -2, and so on. For example:

@fred = ("fred", "wilma", "pebbles", "dino");
print $fred[-1];        # prints "dino"
print $#fred;           # prints 3
print $fred[$#fred];    # prints "dino"

3.4.3 The push and pop Functions

One common use of an array is as a stack of information, where new values are added to and removed from the right-hand side of the list. These operations occur often enough to have their own special functions:

push(@mylist,$newvalue);  # like @mylist = (@mylist,$newvalue)
$oldvalue = pop(@mylist); # removes the last element of @mylist

The pop() function returns undef if given an empty list, rather than doing something un-Perl-like such as complaining or generating a warning message.

The push() function also accepts a list of values to be pushed. The values are pushed together onto the end of the list. For example:

@mylist = (1,2,3);
push(@mylist,4,5,6); # @mylist = (1,2,3,4,5,6)

Note that the first argument must be an array variable name - pushing and popping wouldn't make sense on a literal list.

3.4.4 The shift and unshift Functions

The push and pop functions do things to the "right" side of a list (the portion with the highest subscripts). Similarly, the unshift and shift functions perform the corresponding actions on the "left" side of a list (the portion with the lowest subscripts). Here are a few examples:

unshift(@fred,$a);       # like @fred = ($a,@fred);
unshift(@fred,$a,$b,$c); # like @fred = ($a,$b,$c,@fred);
$x = shift(@fred);       # like ($x,@fred) = @fred;
                         # with some real values
@fred = (5,6,7);
unshift(@fred,2,3,4);    # @fred is now (2,3,4,5,6,7)
$x = shift(@fred);       # $x gets 2, @fred is now (3,4,5,6,7)

As with pop(), shift() returns undef if you give it an empty array variable.

3.4.5 The reverse Function

The reverse function reverses the order of the elements of its argument, returning the resulting list. For example:

@a = (7,8,9);
@b = reverse(@a);    # gives @b the value of (9,8,7)
@b = reverse(7,8,9); # same thing

Note that the argument list is unaltered; the reverse() function works on a copy. If you want to reverse an array "in place," you'll need to assign it back into the same variable:

@b = reverse(@b); # give @b the reverse of itself

3.4.6 The sort Function

The sort function takes its arguments, and sorts them as if they were single strings in ascending ASCII order. It returns the sorted list, without altering the original list. For example:

@x = sort("small","medium","large");
               # @x gets "large","medium","small"
@y = (1,2,4,8,16,32,64);
@y = sort(@y); # @y gets 1,16,2,32,4,64,8

Note that sorting numbers does not happen numerically, but by the string values of each number (1, 16, 2, 32, and so on). In the section "Advanced Sorting" in Chapter 15, Other Data Transformation, you'll learn how to sort numerically, in descending order, by the third character of each string, or by any other method that you choose.

3.4.7 The chomp Function

The chomp function works on an array variable as well as a scalar variable. Each element of the array has its last newline removed. This function can be handy when you've read a list of lines as separate array elements, and you want to remove a newline from all of the lines at once. For example:

@stuff = ("hello\n","world\n","happy days");
chomp(@stuff); # @stuff is now ("hello","world","happy days")