4. Array

A list is a datatype. An array is a variable, that contains a list. An array variable has as prefix the sigil '@'. Example:

@my_array = (1, "xyz", sin(5));
print ("@my_array");# the variable @my_array holds a list with the 3 elements 1, xyz and -0.958924274663138

4.1 Create

4.1.1 Assign a list
@numbers = (1, 2, 3);
@strings = ("abc", "def")
@mix = (1, 2, "abc", "def", 3)
@words = ('this', 'is', 'my', 'list'); # short version: '@words = qw(this is my list);'
@abc = ('A' .. 'Z'); # .. is the so called range operator
@my_numbers = (1 .. 4); # @my_numbers equals (1, 2, 3, 4)
($a, $b) = (1 .. 3); # $a = 1, $b = 2 and 3 is not assigned to anything
($a, $b, $c) = (1, 2); # $a = 1, $b = 2 and $c = NULL
($a, @my_numbers) = (1 .. 5); # $a = 1 and @my_numbers equals (2, 3, 4, 5)
@arr_1 = (1, 2, 3); @sub_arr = (@arr_1[0], @arr_1[1]); # @subarr the list (1, 2)
@arr_1 = (1, 2, 3); @sub_arr = (@arr_1[0, 1]); # same result: @subarr the list (1, 2); @arr_1[0, 1] is called an array slice
@arr_1 = @arr_2 = (1, 2, 3); # both @arr_1 and @arr_2 contain the list (1, 2, 3)
@arr_2 = @arr_1[1, 2]; # if @arr_1 = (1, 2, 3) then @arr_2 the list (2, 3);
@range = (1, 2); @arr_2 = @arr_1[@range]; # same result, but now an array as index
If a scalar is assigned to a list, then the list contains one element:
$x = 1;
@list = $x;
print($#list . "\n"); # the result is: $#list = 0, i.e. a list with one element with index = 0; see 4.2.2
This assigment is the same as:
@list = ($x);
4.1.2 Repetition operator
To construct an array with repeating elements, use the repetition operator 'x':
@my_list = (1) x 5; # @my_list is equivalent to (1, 1, 1, 1, 1)

@my_list = (1, 2) x 5;
print("@my_list"); # output: 1, 2, 1, 2, 1, 2, 1, 2, 1, 2
The repetition operator works on strings also. It can be simulated by a for loop:
@my_list = ();
push(@my_list, 1) for (1..5); # @my_list is equivalent to (1, 1, 1, 1, 1)
4.1.3 Merge arrays
@a = qw/a b/;
@b = qw/c d/;
@ab = (@a,@b); # output: @ab contains the list (a, b, c, d)
4.1.4 Copy an array
To make a full copy:
@words = qw(this is my list);
@words_full_copy = @words;
To make a partial copy:
@words = qw(this is my list);
@words_partial_copy = @words[0,3];# @words_partial_copy contains 'this' and 'list'
@words[0,3] is a so called slice of the array @words.
@words = qw(this is my list);
@words_partial_copy = @words[0..2];# @words_partial_copy contains 'this', 'is' and 'my'
4.1.5 Empty an array (two ways)
@words = qw(this is my list);
@words = ();

@words = qw(this is my list);
undef @words;
4.1.6 Assign array to variables
@mcComposers = qw(Bruckner Beethoven Bach Brahms);
$first_composer, @rest) = @mcComposers; # $first_composer equals Bruckner and @rest contains the other composers
Notice:
@mcComposers = qw(Bruckner Beethoven Bach Brahms);
@all_composers, @rest) = @mcComposers; # @rest contains nothing
An array within a list has been called 'greedy'

4.2 Access

4.2.1 Access elements via an index
A list and an array are zero-based. The first item of a list and an array has the index 0. Notice that a scalar value will be accessed, so the sigil is $. The first element in the array @words is $words[0]
@words = qw(this is my list);
print("The second item of the array @words is '" . $words[1] . "'"); # output: The second item of the array @words is 'is'
4.2.2 Special case: index last element(s) array
@words = qw(this is my list);
$index_last_element = $#words; # which is equivalent to scalar(@words) minus 1...
$index_last_element_alt = scalar(@words) - 1; # scalar(@words) gives the length of the array @words
The last items of a list and an array can be accessed by a negative index.
@words = qw(this is my big list);
print("The third and last item of the array \@words are < $words[2] > and < $words[-1] >");
print("The last item of the array \@words can also be accessed by < $words[$#words] >");
$# is handy
  1. when transversing an array
  2. shorten an array
An example of the last feature:
@mcComposers = ('Bach', 'Beethoven', 'Brahms', 'Bruckner'); # $#mcComposers equals 3, so $mcComposers[$#mcComposers] is Bruckner
$#mcComposers = 2;
@mcComposers contains Bach, Beethoven and Brahms.
4.2.3 Array member
If you want to know if an item is a member of an array, study the examples of 2.2.3 List member.

4.3 Print

@words = qw(this is my list);
print(@words);# output: thisismylist
print("@words");# a quoted array has the effect that the output is now space separated: this is my list
I recommend to use the dot operator when concatenating strings and functions (to avoid unexpected results):
@words = qw(this is my list);
print("The length of the array @words: " . scalar(@words) . "\n");
4.3.1 Print a list several times
You can use the repetition operator x or a for loop:
print("Hello\n" x 10);
print("Hello\n") for ( 1..10 );
4.3.2 Print a list elements by group of n
For this task, you can use the module List::MoreUtils and its function natatime:
use List::MoreUtils ':all';
@list = ('a' .. 'f');
$it = natatime 2, @list;
while (@vals = $it->())
{
     print "@vals\n";
}	

Output:
a b
c d
e f
See Part 3 on Modules. Alternatively:
@list = ('a' .. 'f');
while( ($char_1,$char_2) = splice(@list,0,2)) {
  print("$char_1 $char_2\n");
}
This solution is list-destructive: the array @list is now empty. The non-destructive answer would involve a for loop using indexes to print the characters two by two:
@list = ('a' .. 'f');
for ($i = 0; $i < $#list; $i = $i+2) {
  print("$list[$i] $list[$i+1]\n");
}	
...or simply use a copy of @list. See 4.5.6 on the function splice and chapter 7 on looping.

4.4 Iterate

There are a few ways to iterate over an array. The recommended way is to use 'foreach'.
@abc = qw(a b c);
foreach $item (@abc) {
print("$item\n");
}
This code can be shorter (because the item is only printed): the special variable $_ does the job.'.
@abc = qw(a b c);
foreach (@abc) {
print($_ . "\n"); # Or: 'print; print "\n";'
}
or omitting the array variable:
foreach (qw(a b c)) {
print($_ . "\n");}
Do not add or delete array elements while being processed in a foreach loop!

Iterating an array and creating a new one, while change values.
@mcArray = (1 .. 10);
foreach (@mcArray[2..5, 7, 9]) {
push(@mcArrayNew, $_ += 2); # modifying the values, accessed with the range operator
}
print "@mcArrayNew\n"; # 5 6 7 8 10 12
Notice that the original array is changed as well:
print "@mcArray\n"; # 1 2 5 6 7 8 7 10 9 12

4.5 Operate

4.5.1 Update array elements
An array element can be updates simply by assigning a new value to a value:
@words = qw(this is my big list);
$words[0] = "THIS";
print("@words"); # output: THIS is my big list
@words = qw(this is my big list);
@words[0..2] = qw(THIS IS MY);
print("@words"); # output: THIS IS MY big list
To change all elements of a list, use the repetition operator:
@ones = (1) x 5;
print("@ones"); # output: (1, 1, 1, 1, 1);
@fives= (5) x @ones;
print("@fives\n"); # output: (5, 5, 5, 5, 5);
4.5.2 Remove the last element of an array with 'pop'
@words = qw(this is my big list);
pop(@words);
print("@words"); # output: this is my big
4.5.3 Remove the first element of an array with 'shift'
@words = qw(this is my big list);
shift(@words);
print("@words"); # output: is my big list
4.5.4 Add one or more elements at the end of an array with 'push'
@words = qw(this is my big list);
push(@words, "with 8 elements");
print("@words"); # output: this is my big list with 8 elements
@words = qw(this is my big list,);
@suffix = qw(now with 9 elements);
push(@words, @suffix);
print("@words"); # output: this is my big list, now with 9 elements
4.5.5 Add one or more elements at the beginning of an array with 'unshift'
@words = qw(this is my big list);
@prefix = qw(Hello reader,);
unshift(@words, @prefix);
print("@words"); # output: Hello reader, this is my big list
4.5.6 Add or remove elements of an array with 'splice'
All the operations with pop, shift, push and unshift can also be done with the function 'splice'. But the function has more possibilities.
@abc = qw(a b c);
splice(@abc, 0, 1); # remove the first element from @abc
print("@abc"); # output: b c
@abc = qw(a b c);
splice(@abc, 0, 2); # remove the first two elements from @abc
print("@abc"); # output: c
@abc = qw(c);
splice(@abc, 0, 0, qw(a b)); # replace the first elements of @abc by the elements 'a' and 'b'
print("@abc"); # output: a b
@abc = qw(a b c);
splice(@abc, -1); # remove the last element from @abc
print("@abc"); # output: a b
@abc = qw(a b c);
splice(@abc, 3, 0, qw(d e f)); # add three elements to @abc
print("@abc"); # output: a b c d e f
@abc = qw(a b c);
splice(@abc, 1, 1, qw(x y z)); # replace the second character 'b' of @abc by the elements x y z
print("@abc"); # output: a x y z c
4.5.7 Remove an element of an array with 'delete'
To remove a single element of an array, you can use -if you know its index- 'delete':
@alphabet = 'a'..'z';
print("Array old: @alphabet\n");
$deleted_char = delete($alphabet[25]);
print("Character with index 25 that was removed: $deleted_char"); # output: 'z'
print("Array new: @alphabet\n"); # output: alphabet without the character 'z'
4.5.8 Length array
@words = qw(this is my list);
$array_len = @words; # output: 4. Note that @words is evaluated in scalar context!
print("The array \@words has $array_len elements"); # output: The array @words has 4 elements
Note the double quotes (apostrophes) in the last example. It means that variables will be interpolated. Hence: \@words is used to avoid printing the contents of the array; is replaced by its value.

The same result can be achieved by using the concatenation operator (.):
print("The array \@words has " . scalar(@words) . " elements.");
print('The array @words has ' . scalar(@words) . ' elements.');
Note the single quotes in the last example. It means that the string has to be taken literally. Hence: @words is not replaced by its contents.
4.5.9 Remove duplicates from an array
The best way to remove duplicates from an array is to store unique values in a temporary array. At the end you could copy this to the original array. Notice that the hash datatype offers simpler solutions (Part 2).
@abc = qw(c d a b a b a a c d e);
@abc_temp = ();
for ($i = 0; $i < @abc; $i++) { # @abc is evaluated in scalar context
if (! grep{ /$abc[$i]/ } @abc_temp) { # if the $abc[$i] is not found in @abc_temp, then
push (@abc_temp, $abc[$i]); # add $abc[$i] to @abc_temp
}
}

@abc = sort(@abc_temp);
print "Unique values: @abc\n"; # output: a b c d e
4.5.10 Reorder an array
Reordering an array is quite easy via indices:
@mcComposers = ('Bruckner', 'Beethoven', 'Bach',  'Brahms' );
@mcComposers[0, 1, 2, 3] = @mcComposers[2, 1, 3, 0]; # Bach Beethoven Brahms Bruckner
4.5.11 Math on array elements
@mcArr = ( 1, 2, 3, 4 );
$mcArr[3]++; # @mcArr contains now the elements 1, 2, 3 and 5

4.6 Array: how-to


1. How to count the number of occurrences of a character/substring in a string?

$str="1bus 2bus 3 bus 4 bus";
$count = $str =~ s/bus/bus/g;
$count has the value 4

A way to compute e.g. punctuation characters:
$str="a;b;c,d:e-f-g.";
$count = $str =~ tr/,:;.-/,:;.-/;
$count has the value 7

Consider in above cases the use of an array (which I personally prefer):
$str="1bus 2bus 3 bus 4 bus";
@count_arr = $str =~ s/bus/g;
print(scalar(@count_arr)); 
Output: 4
$str="a;b;c,d:e-f-g.";
@count_arr = $str =~ /[,:;.-]+/g;
print(scalar(@count_arr)); 
Output: 7

In case of multiple character substrings, use a loop. E.g. counting negative numbers, write
$str = "1 -2 3 -5 8 13 -21 34 -53";
$count = 0;
$count++ while ($str =~ /-\d+/g);
$count has the value 4

Alternatively:
@arr = qw(1 -2 3 -5 8 13 -21 34 -53);
@arr_new = grep { $_ < 0 } @arr; 
print("@arr_new: " . scalar(@arr_new)); # output: -2 -5 -21 -53: 4

Counting and determining the positions of character i in the word 'Supercalifragilisticexpialidocious':
$str="Supercalifragilisticexpialidocious"; 
push(@arr_pos, pos($str)) while ($str =~ /i/g); 
print("Positions letter i: @arr_pos \- Number of occurrences: " . scalar(@arr_pos) . "\n");
Output: Positions of character 'i': 9 14 16 19 24 27 31 - Number of occurrences: 7

2. Choose random array element with splice
@colors = qw( aqua black blue fuchsia gray green lime maroon navy olive purple red silver teal white yellow );
$color = splice(@colors, rand @colors, 1); # splice consumes the original array
print($color . "\n"); # Output e.g aqua
print("@colors\n"); # Output: original array without aqua
3. Function call as an array index.
In Perl, you can use a function call as an array index. Here's a simple example:
sub get_index {
    return 2;
}

@array = qw (apple banana cherry);
$result = $array[get_index()];

print $result; # Output: cherry
In this example, the get_index function returns the index 2, and that value is used to access the corresponding element in the @array. Two more examples:
$str = "";
@chars = ('A'..'Z', 'a'..'z', '1'..'9', '!', '@', '#');
$str .= $chars[int(rand(@chars))] for (1 .. 8);
print("$str\n"); # Output e.g eQa#B9j7
@arr = qw(a b);
print($arr[int(rand(100)) % 2]); # Output a or b

Exit: From scalar(string) to array and vice versa

The 'split' function takes a pattern (default space) and a scalar. The scalar will be split in an array.
@abc = sort(split (/;/, "c;b;a"));
print("@abc"); # array output: a b c
The 'join' function takes a string (delimiter) and a list.
@numbers = (1 .. 5);
print(join (" - ", reverse(@numbers)); # string output: 5 - 4 - 3 - 2 - 1