Arrays: ordered lists of values
Holding many values under one name, reaching into the list by position, and the few functions that add, remove, join and slice items.
A name for a list
An array holds many values in order, and its name starts with an at sign: my @scores = (72, 95, 60);. The parentheses hold the values and the commas separate them. An array is the shape you reach for whenever you have more than one of something.
The at sign belongs to the whole list. One item asked out of it is a single value, so it takes a dollar sign and square brackets: $scores[0] is the first score. Positions count from zero, and $scores[-1] counts from the end, which is how Perl says "the last one" without a length calculation.
Growing, shrinking and joining
push adds to the end of a list, pop takes the last item off and answers it, and shift and unshift do the same job at the front. There is no size to declare, so a list grows as you push into it and shrinks as you take things out.
sort answers a new list in order and leaves the original alone. The default sort compares items as text, which is right for names and wrong for numbers, and the chapter on sorting shows the small block of code that fixes it. reverse answers the list backwards, and join glues the items into one piece of text with a separator you choose.
Counting, and taking a slice
An array in front of a number is asked for one value, so scalar @scores is how you ask a list for its count. The chapter on context explains the rule behind that. $#scores is the index of the last item, which is one less than the count.
Square brackets holding more than one position take a slice: @scores[0, 1] is a smaller list of those two items. It is the same idea as reading one item, with the at sign back because the answer is a list again.
A position is an offset from the front
The first item sits at position 0, so the last one sits at the count minus one. $#scores is that last position, and scalar @scores is the count; mixing the two is how a loop runs one item too far or stops one short.
A negative position counts backwards from the end: -1 is the last item, -2 the one before it. Reading past either end does not stop the program; it gives you undef, and use warnings; tells you that you asked for a slot nobody filled.
Lists are copied by value
my @copy = @scores; copies the values into a new list, so pushing into the copy leaves the original alone. That is different from a reference, which the chapter on references comes back to: a reference is a second name for the same data, while a plain list assignment is a duplicate.
The functions that change a list — push, pop, shift, unshift — work on the list you give them. The ones that answer a new list — sort, reverse, a slice — leave the original in place. Knowing which kind you are calling explains most of the surprises in this chapter. A slice belongs on the answering side too: it builds a new list from the positions you name.
An array inside a sentence
An array interpolates in double quotes: "@scores" joins the items with a space, which is handy for a quick look and wrong for a report that needs commas. join ", ", @scores is the explicit form, and it makes the separator a decision rather than a default.
The same rule explains a common surprise: print "@scores\n" prints one line with spaces, while print @scores writes the items run together with no separator at all, because print is a list operator and a list operator adds nothing between its items.
Building a list, reading it, and making it shorter
use strict;
use warnings;
my @scores = (72, 95, 60, 88);
print "count: ", scalar @scores, "\n";
print "first: ", $scores[0], "\n";
print "last: ", $scores[-1], "\n";
push @scores, 100;
print "after push: ", join(', ', @scores), "\n";
my $gone = pop @scores;
print "popped ", $gone, ", count ", scalar @scores, "\n";
my @first_two = @scores[0, 1];
print "slice: ", join('-', @first_two), "\n";
my @names = ('Ada', 'Grace', 'Alan');
print "sorted: ", join(', ', sort @names), "\n";
print "backwards: ", join(' ', reverse @scores), "\n";Six scores, and what happens to them
Run it and watch the count change line by line. Then push two more scores, print the list joined with dashes, and print the count once more to check the number.
A position you never filled holds a value called undef. In arithmetic it counts as zero, and use warnings; is what tells you it was there — so a total that comes out lower than the list suggests is worth a second look.
Three array mistakes are easy to make. $scores[0] is one item and @scores[0] is a one-item slice, so the sigil changes the shape of the answer. $#scores is the last index while scalar @scores is the count. And sort returns a new list: writing sort @scores; on its own throws the sorted list away.
Try these next
- Build a queue with
push, serve two items withshift, and print the count after each move. - Take a slice of the middle two items from a five-item list and join them with a comma.
- Sort a list of names, print it, then print the original list to prove it was not changed.
A queue that moves
Run it and track the list after every operation. Then add two jobs with `push`, serve one with `shift`, and print the remaining count.
Check what you learned
One question at a time. A wrong answer explains itself — take another go.
Part 1 of 5
What is $scores[-1]?
