Perl also enables you to define an ordered collection of values, known as lists, this collection of values can be stored in variables known as array variables.
The array variable name can be any length but it has the following rules
Introducing Lists
A list is a sequence of scalar values enclosed in parentheses
Example Lists | (1, 5.3, "hello", 2) (1, 5.3, $var) # once the element has been assigned the value of $var it remains this (1, "This is string", 3) # you can even use strings as values |
Perl enables you to store lists in special variables designed for this purpose, these variables are called array variables.
Example Array Variables | @array = (1, 2, 3, 4, 5); # here the array variable array contains the list 1, 2, 3, 4, and 5 Note: when the perl interpreter sees a @(at) sign it knows that it is an array. |
The arrays storage units are called elements and you can refer to any element within the array as if it was a scalar value, however when you access a single element the array name must start with a dollar ($) as you are accessing a single scalar value. Elements begin at zero, so when you access the first element it would be $array[0].
Array elements | $scalar = $array[0]; # The first element in the array $scalar = $array[$index]; # you can use the value of a variable to access the elements |
Here is a complete array example
Simple array Example | @food = qw(apple banana orange lemon melon peach plum); # array food will contain 7 elements (0-6) $count = 1; |
Using List Ranges
Suppose you want to define a list of numbers from 1 to 10, you can use the list-range operator two consecutive periods (..) which makes it simpler.
List-Range Example | @array = qw(1 2 3 4 5 6 7 8 9 10); # The old way @array = qw($var1+10 .. $var2+100); # can use complex expressions to create list ranges @days_of_month("01".."31"); # list contains days of the month (including leading zeros) @array = qw( 1 @list 3); # you can even use other arrays to populate arrays |
Assignment and Array Variables
You can copy one array to another
Copy an Array | @food = qw(apple banana orange lemon melon peach plum); @food_allergies = @food; while ($count <= 15) |
Substituting array variables in Strings | @num = (1, 2, 3); print(@num, "\n"); # no spaces between numbers when printed: 123 print("@num\n"); # puts a space between array elements: 1 2 3 |
Assigning scalar variables from arrays | @burgers = ("Big Mac's", "Whopper's"); ($dummy1, $dummy2, $dummy3) = @burgers; # $dummy3 will have null assigned as not enough elements |
Get the length of an array | @food = qw(apple banana orange lemon melon peach plum); $number_of_food_elements = @food; # get the number of elements in array food $count = 1; |
Array Slices | @food = qw(apple banana orange lemon melon peach plum); @part_of_food = @food[2,3,4]; # array will have values orange, lemon and melon @part_of_food = @food[2 ..4]; # same as above using range-list $maximum = @food; # obtain number of elements in food array @part_of_food = @food[2 .. $maximum]; # same as above using range-list and scalar variables |
Array Slices assigning | @food = qw(apple banana orange lemon melon peach plum);
@food[@food .. @food+3] = qw(pineapple strawberry blackberry raspberry); #add to array food $count = 1; |
Overlapping slices | @food = qw(apple banana orange lemon melon peach plum);
@food[1,2,3] = @food[4,5,6]; # we overwrite existing elements using same array food $count = 1; |
Reading an Array from standard input file | @input_file = <STDIN>;
$count = 1; |
Array Library Functions
Perl provides a number of library functions that work on lists and array variables. You can use them to do the following
Sort an array | @array = ("this", "is", "a", "test"); @array2 = sort (@array); # array2 will contain ("a", "is", "test", "this"); @num = (70, 100, 8); Note: sort treats numbers as strings |
Reverse the elements | @array = ("backwards", "is", "array", "this"); @array2 = reverse @array; # array2 will contain ("this", "array", "is", "backwards"); |
Remove the last character from all elements | @list = ("rabbit", "12345", "quartz"); chop (@list); # list will now contain ("rabbi", "1234", "quart"); |
Merge Elements | @list = ("here, "is", "a"); $string = join (" ", @list, "String"); # $string will contain " here is a String", whitespace is the join character Note: the first argument to join is the join character |
Split a string into array elements | $string = "Hello:what:a:nice:day"; @array = split(/:/, $string); # array will contain ("Hello", "what", "a", "nice", "day"); |
Associative arrays use scalar values as subscripts, which means you can have a word represent the index value. Perl uses the percent sign (%) to distinguish an associative array from an ordinary array variable.
Referring to Associative array elements | $fruit{"bananas"} = 1; Note: using the dollar sign ($) tells the perl interpreter that this is a single scalar item and is to be treated as such |
Creating an associative array | %associative_array; # declare an associative array $fruit{"bananas"} = 1; Note: There is no order within the array, elements can be all over the place |
Copying associative arrays from array variables | @fruit = (apples", 6, "cherries", 8, "oranges", 11); %fruit = @fruit; |
Adding an element | $fruit{"bananas"} = 1; |
Deleting an element | delete($fruit{"bananas"}); Note: delete is the only way to delete from an associative array |
Listing the keys | %array = ("foo", "26", "bar", "27"); # keys is commonly used as below Note: in no particular order will the list be returned |
Listing the values | %array = ("foo", "26", "bar", "27"); @values = values(%array); print("@values\n"); foreach $i (values (%array)) { Note: in no particular order will the list be returned |
Looping an associative array | %valle = ("Paul", 35, "Lorraine", "31", "Dominic", 12, "Jessica", 8); ## Using the foreach loop # Using a while loop Note: do not use delete when using each, because the behavior of each unpredictable |
For more on manipulating arrays see List Manipulation.
Data Structures
You can use associative arrays to simulate a wide variety of data structures found in high-level languages, you could implement the following data structures
Linked Lists
A Linked List is a simple data structure that enables you to store items in a particular order. Each element of the linked list contains two fields
Linked List structure | %words = ("alpha", "bravo", "bravo", "Charlie", "Charlie", "delta", "delta", ""); $header = "alpha" |
Complete Linked List Example | # initialize list to empty $header = ""; while ($line = <STDIN>) { # remove leading and trailing spaces $line =~ s/^\s+|\s+$//g; @words = split(/\s+/, $line); foreach $word (@words) { # remove closing punctuation, if any $word =~ s/[.,;:-]$//; # convert all words to lower case $word =~ tr/A-Z/a-z/; &add_word_to_list($word); } } &print_list; sub add_word_to_list { # if list is empty, add first item # if word identical to first element in list, do nothing # see whether word should be the new first word in the list # find place where word belongs # if word already seen, do nothing sub print_list { print ("Words in this file:\n"); |
Structures
Many programming languages enable you to define collections of data called structures. Like Lists, structures are collections of values, each element of a structure, however, has its own name and can be accessed by that name.
Simulate a structure | # C Structure # Perl Simulated structure |
Trees
A tree is similar to a linked list, except that each element of a tree points to more than one other element. The simplest example of a tree is a binary tree. Each element of a binary tree, called a node, points to two other elements, called the left child and right child. Each of these children points to two children of its own and so on, the very last node are called leaf nodes.
The following terminology is used when describing trees
Tree Example | $rootname = "parent"; %tree = ("parentleft", "child1", "parentright", "child2", "child1left", "grandchild1", "child1right", "grandchild2", "child2left", "grandchild3", "child2right", "grandchild4"); # traverse tree, printing its elements &print_tree($rootname); sub print_tree { $leftchildname = $nodename . "left"; |
Databases
Using the above methods you can build quite complex databases, associative arrays can use variable records lengths, are accessible either sequentially or randomly.
The below calculator example is a very complex script, it uses associative arrays and recursive subroutines and the tree structure.
Calculator Example:
To run the calculator program | $calculator Should result in 16 |
very complex example |
# statements which initialize the program $nextnodenum = 1; # initialize node name generator &get_next_item; # read first value from file $treeroot = &build_expr; $result = &get_result ($treeroot); print ("the result is $result\n"); # Build an expression. sub build_expr { local ($currnode, $leftchild, $rightchild); local ($operator); $leftchild = &build_add_operand; if (&is_next_item("+") || &is_next_item("-")) { $operator = &get_next_item; $rightchild = &build_expr; $currnode = &get_new_node ($operator, $leftchild, $rightchild); } else { $currnode = $leftchild; } } # Build an operand for a + or - operator. sub build_add_operand { local ($currnode, $leftchild, $rightchild); local ($operator); $leftchild = &build_mult_operand; if (&is_next_item("*") || &is_next_item("/")) { $operator = &get_next_item; $rightchild = &build_add_operand; $currnode = &get_new_node ($operator, $leftchild, $rightchild); } else { $currnode = $leftchild; } } # Build an operand for the * or / operator. sub build_mult_operand { local ($currnode); if (&is_next_item("(")) { # handle parentheses &get_next_item; # get rid of "(" $currnode = &build_expr; if (! &is_next_item(")")) { die ("Invalid expression"); } &get_next_item; # get rid of ")" } else { $currnode = &get_new_node(&get_next_item, "", ""); } $currnode; # ensure correct return value } # Check whether the last item read matches # a particular operator. sub is_next_item { local ($expected) = @_; $curritem eq $expected; } # Return the last item read; read another item. sub get_next_item { local ($retitem); $retitem = $curritem; $curritem = &read_item; $retitem; } # This routine actually handles reading from the standard # input file. sub read_item { local ($line); if ($curritem eq "EOF") { # we are already at end of file; do nothing return; } while ($wordsread == @words) { $line = <STDIN>; if ($line eq "") { $curritem = "EOF"; return; } # the following two lines fix a problem # in the example as printed in the book $line =~ s/\(/ ( /g; $line =~ s/\)/ ) /g; $line =~ s/^\s+|\s+$//g; @words = split(/\s+/, $line); $wordsread = 0; } $curritem = $words[$wordsread++]; } # Create a tree node. sub get_new_node { local ($value, $leftchild, $rightchild) = @_; local ($nodenum); $nodenum = $nextnodenum++; $tree{$nodenum} = $value; $tree{$nodenum . "left"} = $leftchild; $tree{$nodenum . "right"} = $rightchild; $nodenum; # return value } # Calculate the result. sub get_result { local ($node) = @_; local ($nodevalue, $result); $nodevalue = $tree{$node}; if ($nodevalue eq "") { die ("Bad tree"); } elsif ($nodevalue eq "+") { $result = &get_result($tree{$node . "left"}) + &get_result($tree{$node . "right"}); } elsif ($nodevalue eq "-") { $result = &get_result($tree{$node . "left"}) - &get_result($tree{$node . "right"}); } elsif ($nodevalue eq "*") { $result = &get_result($tree{$node . "left"}) * &get_result($tree{$node . "right"}); } elsif ($nodevalue eq "/") { $result = &get_result($tree{$node . "left"}) / &get_result($tree{$node . "right"}); } elsif ($nodevalue =~ /^[0-9]+$/) { $result = $nodevalue; } else { die ("Bad tree"); } } |
There are two groups of functions that manipulate lists and arrays
The following functions manipulate standard array variables and the lists that they store
grep | extract the elements of a list that match a specified pattern |
splice | enables you to modify the list stored in an array variable, by passing appropriate arguments to splice, you can add elements to the middle of a list, delete portion of a list, or replace a portion of a list. |
shift | remove an item from the beginning a list |
unshift | put an item at the beginning of a list |
push | put an item to the end of a list |
pop | remove an item from the end of a list |
split | split a character string into a list of elements |
sort/reverse | sort a list alphabetically |
reverse | reverse the order of a list |
map | enables you to use each element of a list, in turn as an operand in an expression |
wantarray | wantarray determines if the calling function wants a scalar or array variable returned |
Examples |
|
grep | # grep (<pattern>, <searchlist>) $line = "This line of input contains 8, 11 and 26."; @numbers = grep(/^\d+[.,;:]?$/, @words); Note: you can also use grep with the file-test operators |
splice | # retval = splice(<array>, <skipelements>, <length>, <newlist>); # Replace # Appending # Deleting |
shift/unshift | ## add or delete from the left side of the array, element 0 @array = qw(1 2 3 4); $first_element = shift(@array); print ("Array: @array"); unshift(@array, $first_element); |
push/pop | ## add or delete from the right side of the array, last element @array = qw(1 2 3 4); $first_element = pop(@array); print ("Array: @array"); push(@array, $first_element); |
split | $string = "one::two::three::four::five::six"; |
sort | @array = qw( one two three four five six);
@sorted = sort(@array); |
reverse | @array = qw( one two three four five six);
@reversed = reverse(@array); |
map | # map(<expression>, <array>); # The map function uses the system variable $_ for each element @array = qw(100 200 300 400); @results = map($_+1, @array); print("@results"); |
wantarray | @array = &mysub(); # using an array the wantarray will return true $scalar = &mysub(); # using an scalar the wantarray will return false sub mysub { |
Here are some equivalent comparisions using the splice command assuming <CODE class=inline><SPAN class=i>($[</SPAN> == <SPAN class=n>0</SPAN> and <SPAN class=i>$#a</SPAN> >= <SPAN class=i>$i</SPAN></CODE> )
Add an item on the end of a list | push(@a,$x) | splice(@a,@a,0,$x) |
Remove an item from the end of a list | pop(@a) | splice(@a,-1) |
Remove an item from the beginning of a list | shift(@a) | splice(@a,0,1) |
Add an item to the beginning of a list | unshift(@a,$x,$y) | splice(@a,0,0,$x,$y) |
set a element array to a value | $a[$x] = $y | splice(@a,$x,1,$y) |
To create a queue you would use push and shift, and to create stack you would use push and pop.
The following functions manipulate associative arrays
keys | returns a list of subscripts of the element of an associative array |
values | returns a list consisting of all the values in an associate array |
each | returns an associative element as a two element list |
delete | deletes an associative array element |
exists | enables you to determine whether a particular element of an associative array exists. |
Examples |
|
keys | %array = ("foo", "26", "bar", "27"); # keys is commonly used as below Note: in no particular order will the list be returned |
values | %array = ("foo", "26", "bar", "27"); @values = values(%array); print("@values\n"); foreach $i (values (%array)) { Note: in no particular order will the list be returned |
each | %array = ("foo", "26", "bar", "27"); @each = each(%array); print("@each\n"); foreach $i (each (%array)) { Note: in no particular order will the list be returned, also do not use delete when using each, because the behavior of each unpredictable |
delete | %array = ("foo", "26", "bar", "27");
$retval = delete($array{"foo"}); # returns the deleted elements value 26 foreach $i (keys (%array)) { print $retval; |
exists | %array = ("foo", "26", "bar", "27");
if ( exists($array{"foo"}) ) { |
When using associative arrays do not use push, pop, shift or splice because the position of any particular element in the array is not guaranteed.