Array Variables in Perl

This tutorial walks through using array variables in Perl.

Simple Arrays
You’ve already seen simple arrays. We used them for the “command line” variables. Simple arrays begin with the “@” symbol. If you want a specific value from the array, you index that value using its number in the array. If you want the first item from the array, you ask for “$ARGV[0]”. If you want the third item, use “$ARGV[2]”.

Arrays always use the “@” symbol. Scalar variables always use the “$” symbol. A piece of an array is always a scalar. (You can’t have arrays inside of arrays in simple Perl.) That's why you use “@” to refer to the entire array, and “$” to refer to items within the array. If you want to know how many values are in an array, use the scalar variable $#ARRAY. This is actually the index of the last element, so for the count, you’ll need to add one. For example:

@Names = ("John","Jerry","Steve","Hsiao-Ping","Daniel");
$NameCount = $#Names+1;
print "There are $NameCount names in the array.\n";
foreach $Counter (0..$#Names) {
$HumanCounter = $Counter+1;
print "Name number $HumanCounter is $Names[$Counter].\n";
}
@Names = sort(@Names);
foreach $Name (@Names) {
print $Name;
if ($Name eq $Names[$#Names]) {
print ".\n";
} else {
print ", ";
}
}

The above program should produce the following:

/u5/jerry> arraytest
There are 5 names in the array.
Name number 1 is John.
Name number 2 is Jerry.
Name number 3 is Steve.
Name number 4 is Hsiao-Ping.
Name number 5 is Daniel.
Daniel, Hsiao-Ping, Jerry, John, Steve.

Can you spot a possible problem in the above program? You’d better, because fixing it is going to be an exercise!

Shifting Array Values
You will often shift array values when you are pulling command line options from a command line that can also include filenames. In general on Unix, when a command takes both options and filenames as arguments, the filenames come last. The ‘shift’ function allows you to slide the first element of the array out from under the rest of the elements. It completely removes that element from the array.

while ($ARGV[0] =~ /^-/) {
$currentArg = shift(@ARGV);
#figure out which option this is
#blah blah
}
#go ahead and do the rest on the filenames
while (<>) {
print;
}

Getting a Numeric Array
Suppose you want an array of numbers from 5 to 1000. You could construct it by hand, but Perl will make it for you. We‘ve already done it once with “foreach”:

@Counters = (5..1000);
This numeric construction always counts up by one. If you want to count down instead of up, you can reverse the array:
@Counters = reverse(@Counters);

or, you could combine it into one line with

@Counters = reverse(5..1000);

Sorting Arrays
You can sort arrays using simple or complex methods. The simplest way to sort an array is to use the sort function:

@Names = sort(@Names);

Sort always sorts in alphabetical order. If you want to sort in numerical order, you need to use the more complex version:

@Numbers = sort numerically @ARGV;
sub numerically {
return $a <=> $b;
}

In this case, we’re telling ‘sort’ to use the ‘subroutine’ numerically to determine how to sort the array. A ‘subroutine’ is a bit of code that can be reused without having to retype it. In this case, a sort subroutine is a special subroutine that has its arguments automatically put into $a or $b. The subroutine must return an integer. If this integer is less than zero, sort assumes that $a comes before $b. If this integer is greater than zero, sort assumes that $b comes before $a. If the integer is zero, sort assumes it doesn’t matter.

The operator ‘<=>‘ returns -1 if the item on the left is less than the item on the right, zero if they’re equal, and 1 if the item on the right is less than the item on the left. Go ahead and test it:

print $ARGV[0] <=> $ARGV[1];
print "\n";

You can do whatever you want in your subroutine, as long as it returns predictable integer values based on $a and $b.

The equivalent to ‘<=>‘ for strings is ‘cmp’. Go ahead and replace ‘<=>‘ above with ‘cmp’ and try different strings on the command line.

Other Array Functions

join(@array,$string)
returns the elements of array using string as a delimiter

pop(@array)
returns and removes the last element of array

push(@array,$string)
puts string onto the end of array. Does not return ‘array’.

shift(@array)
returns and removes the first element of array

split($string1,$string2)
returns string2 split into an array wherever string1 occurs

Associative Arrays
Associative arrays start tapping into the database functions of Perl. An associative array is a list of elements, but each element in the array is accessed by an index value that does not have to be a number.

$LastNames{'Jerry'} = 'Stratton';
$LastNames{'John'}='Paul';
$LastNames{'Steve'}='Spear';
print $LastNames{$ARGV[0]};
print "\n";
This array stores the values “Stratton”, “Paul”, and “Spear”. In order to access those values, I need to know the value they’re associated with:
20: lastname Jerry
Stratton
21: lastname Steve
Spear

You’ll use the “delete” function to delete an element of an associative array:

$deletedName = delete $LastNames{'Steve'};

If you need to get a list of all the keys in an associative array, use the keys function:

@FirstNames = keys(%LastNames);
foreach $key (@FirstNames) {
print "$key: $LastNames{$key}\n";
}

Like scalar variables and simple arrays, associative arrays have their own prefix, the “percent” sign. Like simple arrays, you’ll only use the percent sign when referring to the associative array as a whole. When referring to individual elements, you’ll continue to use the dollar sign.

Let’s take a look at a simple program for viewing the passwd file in Unix:

$PASSWDFILE = '/var/yp/passwd';
open PASSWDFILE;
while (<PASSWDFILE>) {
@lineItems = split(':');
$username = $lineItems[0];
$passwords{$username} = $lineItems[1];
$userids{$username} = $lineItems[2];
$groupids{$username}=$lineItems[3];
$names{$username}=$lineItems[4];
$homes{$username}=$lineItems[5];
$shells{$username}=$lineItems[6];
}
close PASSWDFILE;
foreach $User (@ARGV) {
$User = lc($User);
print uc($User);
print ":\n";
print "\tPassword: $passwords{$User}\n";
print "\tUser ID: $userids{$User}\n";
print "\tGroup ID: $groupids{$User}\n";
print "\tReal Name: $names{$User}\n";
print "\tHome Directory: $homes{$User}\n";
print "\tDefault Shell: $shells{$User}\n";
print "\n";
}

This script uses usernames as the ‘key’ for this associative array. It could just as well have used user id. The key has to be something that will be unique for each ‘record’.

Note that in the ‘split” line, we’ve left out the $_. Perl will often assume that that’s what you meant, and in this case it works just fine.We’ve also explicitly opened a file here for the first time. We’ll have more on that later, but we put the filename into a scalar variable, and made sure that scalar variable was in all capitals. This allowed us to use the simple form for opening the filename contained in that variable. And don’t forget that we closed it at the end! If you look at the ‘while’, you’ll see that it looks pretty much the same as when we used the <STDIN> filehandle.

About this Tutorial
This tutorial is written by Jerry Stratton and is published under the GNU Free Documentation License.


0 comments:

Post a Comment