PrevIndexNext

# Arrays

Arrays are used when you want to deal with many things at one time. And when you want to keep those things in a certain order.

Perl has arrays just like C, Java and C++ but, of course, it does it in a different and very convenient way.

The magic letter preceding an array identifier is the at sign '@'.

Two mnemonics:
@ looks like an a (for array)
\$ looks like an s (for single/scalar)

## Initializing an array

@nums = (1, 3, 2, 5, 4);
On the right hand side we put a parenthesized comma separated list of scalars.

Other examples:

@names = ("Joe", "Jon", "Jeff"); \$pi = 3.14; @vals = (2.71828, \$pi, -1); @stuff = ("Elle", 23, "Rick", 56, "Walter", 23);
The last example shows that you don't have to have the same kind of value in each element of an array. Just scalars.

## Referencing

To reference an individual element of an array we put an integer in square brackets - this number is called the 'index' (This is not the same as the function 'index'). The first element of the array is at index 0 not 1.
print \$nums[3]; # prints 5 print \$names[1]; # prints Jon
Notice that the preceding character is '\$' not '@'. Individual elements are scalars.
\$nums[1] = 8; # replaces the 3 with 8. \$nums[\$i+1] = \$n*sqrt(56); \$nums[10] = 11;
The last one above extends the array @nums (as initialized above). Elements that are as yet unassigned have the value of 'undef'. Arrays are quite dynamic - they grow and shrink as needed. This does certainly not happen in C, C++ or Java.

## Last index and Size

The index of the last element of @nums is \$#nums. This syntax is punctuationally intense but does work. If you assign an array to a scalar the scalar will get the current size of the array.
@counts = (1, 34, 2, 56, 234); print \$#counts; # prints 4 \$n = @counts; print \$n; # prints 5

## Printing and Interpolating

Arrays and arrary elements can be printed and interpolated just like scalars:
@nums = (1, 2, 3); print "@nums"; # 1 2 3 print "the 3rd number is \$nums[2]\n"; print @nums; # 123
Note that spaces are inserted between elements when interpolating but that when you give an array to print its elements are all concatenated to each other - just as if you had given each element as a separate parameter to print.

@vals = ();

## Assigning arrays

You can copy literal lists and arrays to another array:
@nums = (1, 2, 4, 5); @counts = @nums;

## Pop, Push, Shift, Unshift

The functions 'pop' and 'push' operate on the end of the array.
@nums = (11, 3, 2, 4); \$n = pop @nums; # removes 4 \$m = pop @nums; # removes 2 push @nums, 12; # @nums is now (11, 3, 12)
In the same way, 'shift' and 'unshift' work on the beginning of the array.
@nums = (11, 3, 2, 4); \$n = shift @nums; # removes 11 \$m = shift @nums; # removes 3 unshift @nums, 45; # @nums is now (45, 2, 4)

## Reading all Lines into an array

How can you read all the lines of a file into an array? There are many ways. A favorite 'motto' of the Perl community is this:
There's More Than One Way To Do It
This has the acronym TMTOWTDI - pronounced "Tim Toady".

First way:

\$i = 0; while (\$name = <IN>) { \$names[\$i] = \$name; ++\$i; }
Second way:
while (\$name = <IN>) { push @names, \$name; }
Third way:
@names = <IN>;
Cryptic? Perhaps. But very nice.

## Command line arguments

When you invoke a perl program (e.g. hello) on the command line you can put extra arguments after the program name:
% perl hello Joe 35 or % hello June 6 or C:> perl hello.pl Martha 51
Command line arguments are automatically put into an array named @ARGV. You can use it just like any other array. It is no different except that it is initialized for you. Study on this code:
% hello -d Charles 45 \$debug = 0; if (\$ARGV[0] eq "-d") { \$debug = 1; shift @ARGV; # toss away the argument } if (@ARGV != 2) { # in scalar context - hence the size die "usage: hello [-d] name age\n"; } \$name = shift @ARGV; \$age = shift @ARGV;

## Looping over each element of an array

Again, there are many ways.

First way:

for (\$i = 0; \$i < @names; ++\$i) { print "hello \$names[\$i]\n"; }
Note that @names appears in scalar context and hence the comparison is done against the size of the array.

Second way:

while (@names) { \$name = shift @names; print "\$name\n"; }
This way will leave the array empty - probably not what you wanted.

Third way:

foreach \$n (@nums) { print "\$n\n"; }
Nice, huh! If you modify \$n within the loop it will change the elements of the array so be careful!

You can actually use 'for' as a synonym for 'foreach'. The 'for' statement has two different syntaxes. The one we saw earlier - with the 3 parts (initialization, test, increment) within the parentheses separated by semicolons ';' like so:

for (\$i = 0; \$i < 10; ++\$i) { print "\$names[\$i]\n"; }
and the other with an array inside the parentheses as above.
for \$n (@names) { print "\$n\n"; }

The more you learn about the way that Perl deals with arrays the less you will use indexes. Sometimes indexes are necessary and sometimes they make for clearer code.

# Exercises

1. Read a series of numbers from STDIN until a -1 is entered. Store them in an array. Ask the user which number they would like to see. When they enter 'q', quit. For example:
2 31 4 1 56 3 -1
And then:
Which number? 4 1 Which number? 6 3 Which number? 12 Not that many - only 6 numbers! Which number? q
2. Make a reverse polish notation calculator (Hewlett Packard style) that implements + and -.
4 5 + # prints 9 (4 + 5) 3 - # prints 6 (9 - 3) 1 + # prints 7 (6 + 1)
Such calculators work by implementing a 'stack' or 'pile'. Numbers that are read are simply put on top of the pile (like 4 and 5 above). Operators like + and - take two numbers off the pile, do the appropriate operation with those two numbers (4+5=9), and put the resulting number (9) back on the pile after printing it.

The functions push and pop are ideal for this exercise.

3. Make program called 'pick'.
% pick fname linenum1 linenum2 ...
It will print the requested lines of the file. The line numbers can be in any order. Give an error message if the line number is too large.