Perl Arrays and Lists

Perl has a data structure that is strictly known as array of scalars. This structure is more commonly known as an array or a list. Perl's arrays can be used as a simple list, stack, or even the skeleton of a complex data structure. Anything beginning with an @ symbol is an array.

Arrays and lists:

Arrays are closely related to (but not the same as) lists. A Perl list is a sequence of  comma separated values usually in a set of parentheses. A Perl array is a container for a sequence of values (that is, a container for a list). Lists are commonly used to initialize arrays. Assigning a list to an array places each item in the list in a consecutive element of the array. Lists can also be used to extract values from arrays.

Using Arrays as an Indexed List:

The most common method of  using an array as an indexed list is to directly assign the array all of its values at creation. The following example sets the array variable @months to the months of the year. There are two items to mention regarding the example below: the placeholder JUNK and the keyword qw. Arrays start at index 0: junk is the placeholder so Jan could be 1.

@months = qw ( JUNK Jan Feb March April May June July Aug Sept Oct Nov Dec);
@array = qw (a b c d e);
   is equivalent to
@array = ("a", "b", "c", "d", "e");

The keyword qw is a shortened form used to extract individual words from a string. The above example can also be done in the following manner:

$months[0] = "JUNK";
$months[1] = "Jan";
...$months{12} = "Dec";
@home = ("a", "b", "c");
($m, $n, $o) = @home;
$home[0] = "a";
$home[1] = "b";
$home[2] = "c";

Notice when you assign the array elements directly, you use the $ character, not the @ character.

List constructor operator:

The list constructor operator could save you the trouble of listing all the values if you are using numbers:

(1 .. 5) # is equivalent to (1, 2, 3, 4, 5)
(2 .. 6, 59, 98) # is equivalent to (2, 3, 4, 5, 6, 59, 98)
($x .. $y) # if $x and $y are two numbers, .. is the range in between

Assignment:

You can assign values to arrays using all the methods discussed above. What we have been doing above is assigning scalar values to an array. Perl also allows you to assign an array to another array.

@onearray = @anotherarray;

You can also mix things up:

@hexcharacters = qw(a b c d e f);
@palindrome = (1 .. 9, @hexcharacters, reverse(@hexcharacters), 9, 8, 7, 6, 5, 4, 3, 2, 1);
# ( 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, f, e, d, c, b, a, 9, 8, 7, 6, 5, 4, 3, 2, 1 )

Don't be intimidated by the line noise. @hexcharacters is assigned the values a, b, c, d, e, and f. In @palindrome, first we are assigning the values 1, 2, 3, 4, 5, 6, 7, 8, and 9 using the list constructor operator. Then we are assigning the array @hexcharacters. The function reverse() does what you think it does, it reverses the array @hexcharacters. You can take on from there. The point is that you have a lot of ways to assign an array and you can use them simultaneously if you wish or need to do so.

Note that @hexcharacters is not the ninth element of @palindrome, the ninth element is a. In fact, @hexcharacters is not even an element of @palindrome. This is because a list cannot contain another list as an array. If you still want an array to be an element of another array, then use a list reference (which we will talk about in the references lesson).

Going back to the paragraph before the previous one, Perl offers you a great degree of flexibility and a lot of ways to do the same thing. Well, most of the new ways of doing things come from your ingenuity, but you can't do much if the language won't allow it. To get a feel of what I mean see below:

($one, $two, $three) = (23, 43, 37); # $one = 23, $two = 43, and $three = 37
@sqr[1..4] = (1, 4, 9, 16) # range of indices
@sqrt[1, 49, 9, 16, 4] = (1, 7, 3, 4, 2); # non-sequential indices
@inverse[@sqr] = (1, 0.25, 0.1111, 0.0625); # indices stored in another array
($one, $two) = ($two, $one) # swaps $one and $two
($d, @array) = ($x, $y, $z) # $d = $x and @array = ($y $z)
($five, @numbers) # This moves the first element of @numbers to $five

We have seen that scalars can be assigned to arrays. Arrays can also be assigned to arrays. We know from the previous lesson that scalars can be assign to scalars. Can we assign an array to a scalar? The answer is yes, but don't go away, yet. Yes you can assign it, but the scalar would not get the array, it would get the size of the array.

@array = (23, 34, 45);
$scalar = @array; # $scalar = 3, the lengh of the array
($scalar) = @array; # $scalar = 23, the first element of the array

You can assign values to more than one arrays at the same time:

@array1 = @array2 = @array3 = (21, 324, 324);

Accessing array elements selectively:


Perl arrays are indexed 0 to n. Suppose if @array is an array of 23 elements, then $array[0] is the first element and $array[22] is the last element. To copy an element's value to a scalar:

$scalar = $array[9];

Array Arithmetic:

$array[5]++; # increment sixth element of @array


$n = 5;

$array[$n];        # accesses
the sixth element of the array

$array[++$n];      # accesses the seventh
element of the array

$array[--$n];      # would decrement $n
and then use as an index

$array[$n] += 5;   # adds 5 to the nth element of the
array


($array[0], $array[1]) = ($array[1], $array[0]); # swaps two elements
of the array. You can also do this for the entire array

You can also use negative values to access perl arrays. They access the
array in reverse:

@array = (23, 34, 4, 3421, 234);

$array[-2];      # 3421

$array[-3];      # 4

Slicing: the act of accessing a list of elements from an array. Here is
how you do it:

@array[3, 4];                     
# is equivalent to ($array[3], $array[4])


@array[3, 4] = @array[4, 3];      
# slice and swap

@array[3, 10, 15] = (4, 98, 120);  # slice and assign values

@array[4, 6, 9] = @array[2, 2, 2]; # assign the value of $array[2]
to $array[4], $array[6], and $array[9]

End of Array:

Where does the array end? Every programmer using an array needs to
know the answer to this question, regardless of the language he is using.
Java does not allow a program to access an array element out of bound (Meaning
element which is out of the range of an array. For example the 100th element
is out of bound of a 10 element array). C++ allows you access an element
out of bound but that attempt will return a garbage value. Perl allows
you to access an element out of bound but that element will return the
value undef meaning undefined. Which method do you think is the best? Java
or Perl?

C++ does not allow a program to extend an array dynamically. For example
you have an array of 10 elements. Then the program adds an element while
running. This is not allowed in C++. Its not allowed in Java but Java provides
a vector which can be resized dynamically. Dynamic resizing is allowed
in perl. It does not have to be in order. Meaning that if there is a 10
element array, you can add the 19th element without having to add eleventh,
twelfth, ... eighteen element. All elements in between would have the value
undef.

@array = (1 .. 4);


$array[6] = "perl";    # (1, 2, 3, 4, undef, undef,
perl)

Occasionally you would have to access the last element of the array. You
can access the last element by using $#arrayname. You can also
use -1 as an index.

@array = (12, 43, 54, 213);

print $array[-1];          
# 213

print $#array;             
# element number 3


print $array[$#array];      # 213

List Value and Arrays

@stuff  = ("one", "two", "three");

$stuff = @stuff;                    
# $stuff = 3

$stuff = ("one", "two", "three");    # $stuff =
3

LISTs do automatic interpolation of sublists. That is, when a LIST is evaluated,
each element of the list is evaluated in a list context, and the resulting
list value is interpolated into LIST just as if each individual element
were a member of  LIST. Thus arrays lose their identity in a LIST.

(@foo, @bar, &Somesub)

contains all the elements of @foo, followed by all elements of @bar, followed
by all the elements returned by the subroutine named Somesub when it's
called in a list context. You can use a reference to an array if you do
not want it to interpolate. Null list is represented by ().

@days + 0;         
# implicitly forces @days into a scalar context

scalar(@days);      # explicitly forces
@days into a scalar context


@whatever = ();     # assigning a null list

$#whatever = -1;    # assigning a null list

Functions:

Using Arrays as Stacks (push and pop):

When I was learning C++, I had to go through a lot of pain to learn
how to create my own stack. I didn't have to go through the same pain in
Java because there is a class by the name of stack defined in the language.
Learning to use it took a little time but was a blessing when compared
to C++. In perl, you can convert an array into a stack in one line and
then back in another line! No wonder a lazy programmer like myself got
hooked to Perl. To utilize an array as a stack, use the push and pop functions:

Suppose LIFO = (1, 2, 3)

push(@myList, "LIFO");   # @myList = (1, 2, 3)


$one = 34;

push(@myList, $one);     # @myList = (1, 2,
3, 34)

push(@myList, 99, 100);  # @myList = (1, 2, 3, 34, 99, 100)

$index = pop(@myList);   # $index = 100

The push function takes an array and a list of elements to append to it.
It then appends them and returns the new length of the array. The pop function
removes the last element of an array and returns that element. If the array
is empty, it returns undef.

shift and unshift:


The push and pop functions deal with the highest subscripts. This is
sometimes called the right side of an array. Now that we discovered that
an array can also be treated like a stack, it seems a bit awkward to call
it a array. This is why the word is used to refer to an array. The shift
and unshift functions deal with the lowest subscripts. This is sometimes
called the left side of the array:

unshift(@array, $a);       
# like @array = ($a, @array);

unshift(@array, $a, $b);    # like @array = ($a,
$b, @array);

$x = shift(@array);        
# like ($x, @array) = @array;

@array = (5, 6, 7);

unshift(@array, 2, 3, 4);   # @array is now (2, 3, 4,
5, 6, 7)


$x = shift(@array);        
# $x gets 2, @array is now (3, 4, 5, 6, 7)

The unshift and shift functions work just like push and pop respectively,
except that they add elements to the start of an array instead of the end.

splice

The push, pop, shift, and unshift functions are special cases of a
more general function called splice, which changes the elements of an array.
The splice function takes four arguments:

the array to be modified

the index at which it's to be modified

the number of  elements to be removed (starting at the index specified
in the previous argument)

a list of extra elements to be inserted at the index (after the previous
elements are removed)

The function returns a list of the elements removed from the array being
modified.

The following is from programming perl:

splice ARRAY, OFFSET, LENGTH, LIST

splice ARRAY, OFFSET, LENGTH

splice ARRAY OFFSET

This function removes the elements designated by OFFSET and LENGTH from
an array, and replaces them with the elements of LIST, if any. The function
returns the elements removed from the array. The array grows or shrinks
as necessary. If LENGTH is omitted, the function removes everything from
OFFSET onward. The following equivalences hold (assuming $[ is 0):

 

 


Direct Method Splice Equivalent
push(@a, $x, $y) splice(@a, $#a+1, 0, $x, $y)
pop(@a) splice(@a, -1)
shift(@a) splice(@a, 0, 1)
unshift(@a, $x, $y) splice(@a, 0, 0, $x, $y)
$a[$x] = $y splice(@a, $x, 1, $y)

The splice function is also handy for carving up the argument list passed
to a subroutine. For example, assuming list lengths are passed before lists:

sub list_eq {           
# compare two list values

   my @a = splice(@_, 0, shift);

   my @b = splice(@_, 0, shift);

   return 0 unless @a == @b;           

# same len?

   while (@a) {

      return 0 if pop(@a) ne pop(@b);

   }

   return 1;

}

if (list_eq($len, @foo[1..$len], scalar(@bar), @bar)) { ... }

It would probably be cleaner just to use references for this, however.

reverse

The reverse function reverses the order of the elements of its arguments,
returning the resulting list. The original list is always unaltered, reverse
works on a copy.

@array1 = (234, 89, 36, 98);

@array2 = reverse(@array1);    # @array2 = (98,
36, 89, 234)

sort:

The sort function does what you think it does, it sorts. Note the way
numbers are sorted.

sort("one", "two", "three");  # one three two


sort(1, 2, 12, 24);          
# 1, 12, 2, 24

chomp:

The chomp function works on an array variable as well as a scalar variable.
This function removes the last element.

@stuff = ("one\n", "two\n", "three");

chomp(@stuff); one two three

Arrays
Construct
Meaning
@days Same as ($days[0], $days[1],....$days[n])
@days[3..5] Same as ($days[3], $days[4], $days[5])
@days[3..5] Same as @days[3, 4, 5]
@days{'Jan', 'Feb'} Same as ($days{'Jan'}, $days{'Feb'})