Introducción

Una variable array puede almacenar una secuencia de valores escalares, los cuales se identifican unívocamente a través de un índice.

@days  = (1,2,3,4,5,6,7);

El operador ..

El operador .. toma dos numeros $ x_1$ y $ x_2$ y devuelve una lista con los enteros entre esos dos números:

  DB<1> @b = 4..8
  DB<2> p @b # Los elementos son mostrados sin separación
45678
  DB<3> p "@b" # Interpolación: los elementos son separados
  4 5 6 7 8
  DB<4> x @b
0  4
1  5
2  6
3  7
4  8
  DB<5> @a = 2.1 .. 4.1
  DB<6> x @a
0  2
1  3
2  4

Este operador devuelve una lista vacía cuando $ x_2 < x_1$.

  DB<6> @c = 5..4
  DB<7> p @c

  DB<8> x @c
  empty array

Acceso a los Elementos de un Array

Los valores individuales de un array se acceden precediendo de un $ el nombre del array:

foreach my $i (0..5) {
  print $days[$i]," es un día laboral/n";
}

El índice del primer elemento es cero.

Si se omite la variable que se usa para indexar en el for, se usará la variable mágica por defecto $_. Así el bucle anterior es equivalente a:

foreach  (0..5) {
  print $days[$_]," es un día laboral/n";
}

Troceado de arrays

Un slice o trozo de un array resulta de indexar el array en un subconjunto de índices:

    @days               # ($days[0], $days[1],... $days[n])
    @days[3,4,5]        # @days[3..5]
    @tragedy[3,4,5] = ("Mcburger", "King Leer", "Hamlet, A Pig in the City")
    @sqrt[1,49,9,16,4] = (1, 7, 3, 4, 2) # índices desordenados
    @sqr[1..4] = (1, 4, 9, 16)
    @inverse[@sqr] = (1, 0.25, 0.111, 0.0625); # indexado en un array
    @list[5..9] = reverse @list[5..9]; # invierte los elementos del 5 al 9
                                       # en list
    @a[$n, $m] = @a[$m, $n]; # intercambiamos $a[m] y $a[n]

La función reverse

El operador reverse toma los elementos de una lista y devuelve la lista en orden inverso:

  DB<1> @a = 1..10
  DB<2> @a = reverse @a
  DB<3> p "@a"
10 9 8 7 6 5 4 3 2 1

En un contexto escalar, cuando reverse es aplicado a una lista devuelve la cadena resultante de concatenar los elementos de la lista en orden inverso:

  DB<6> @a = 1..10
  DB<7> $b = reverse @a
  DB<8> p $b
01987654321
  DB<9> @a = qw{one two three}
  DB<10> $x = reverse @a
  DB<11> p $x
eerhtowteno

Si se aplica a una cadena en un contexto escalar produce la recíproca de la cadena:

  DB<29> q
lhp@nereida:~/public_html/cgi-bin$ perl -wde 0
main::(-e:1):   0
  DB<1> $a = "dabale arroz a la zorra el abad"
  DB<2> p scalar(reverse($a))
daba le arroz al a zorra elabad

Sin embargo, en un contexto de lista la cadena queda sin modificar:

  DB<3> p reverse($a)
dabale arroz a la zorra el abad

Tenga cuidado si esta trabajando en un entorno que usa UTF-8. En ese caso reverse puede producir un resultado erróneo:

lhp@nereida:~/Lperl/src$ perl -we 'print reverse("dábale arroz a la zorra el abad")."\n"'
daba le arroz al a zorra elab##d

Para solucionarlo es necesario usar el módulo utf8 y poner el fichero de salida en modo :utf8:

lhp@nereida:~/Lperl/src$ cat -n reverse.pl
 1  #!/usr/local/bin/perl -w
 2  use strict;
 3  use warnings;
 4  use utf8;
 5  binmode STDOUT, ':utf8';
 6  my $x = shift || "dábale arroz a la zorra el abad";
 7  print reverse($x)."\n"; # Contexto escalar forzado por el "."
Cuando se ejecuta se obtiene:
lhp@nereida:~/Lperl/src$ reverse.pl
daba le arroz al a zorra elabád

Dinamicidad de los Arrays

Una asignación a un elemento que no existe lo crea:

$days[9] = 10;

Los elementos extra $days[6], $days[7] and $days[8] son asi mismo creados y se inicializan al valor indefinido undef.

Ultimo Indice de un Array

La variable $#days almacena el índice del último elemento del array.

Indices Negativos

En Perl, los índices negativos cuentan desde el final del array (-1 es el último elemento).

DB<1> @a = 1..10
DB<2> $a[-1] = 1
DB<3> p "@a"
1 2 3 4 5 6 7 8 9 1
DB<4> $a[-20] = 0
Modification of non-creatable array value attempted, 
subscript -20 at (eval 18)
[/usr/share/perl/5.6.1/perl5db.pl:1521] line 2.
DB<5> p $#a
9

Número de elementos de un Array

Si el array completo es accedido en un contexto en el que se espera un escalar numérico, (scalar context) el resultado es un escalar conteniendo el número de elementos del array.

my $i = 0;
while ($i < @days) {
  print $days[$i++],"\n";
}

La función scalar

La función scalar fuerza un contexto escalar:

  DB<1> @a = 0..9
  DB<2> p "@a\n"
0 1 2 3 4 5 6 7 8 9

  DB<3> p "\@a = ",@a,"\n"
@a = 0123456789

  DB<4> p "\@a = ",scalar @a,"\n"
@a = 10

Diferencias entre Arrays y Listas

Los arrays estan muy relacionados, pero no son lo mismo que las listas. Una lista en Perl es una secuencia de valores separados por comas, normalmente entre parentesis. Un array es un contenedor para una lista. Las listas pueden usarse para extraer valores de los arrays. Por ejemplo:

($d1, $d2) = @days;

Asignación a Listas y Asignación a Arrays

Se puede asignar listas de valores a listas de variables:

($a, $b) = ($b, $a);
que intercambia los valores de $a y $b.

En una Asignación a una lista, si hay mas variables en la lista que elementos en la parte derecha , las variables extra quedan indefinidas (undef). Si por el contrario hay menos variables que elementos en la parte derecha, los elementos extra son ignorados.

Veamos un ejemplo:

lhp@nereida:~/Lperl/src$ perl -wde 0
main::(-e:1):   0
  DB<1> @a = 1..3
  DB<2> @b = 1..5
  DB<3> ($a,$b) = @a
  DB<4> x ($a,$b)
0  1
1  2
  DB<5> ($c,$b,$a) = (2,7)
  DB<6> x ($c,$b,$a)
0  2
1  7
2  undef
  DB<7> ($c,$b,$a) = (2,7,9,12,@b)
  DB<8> x ($c,$b,$a)
0  2
1  7
2  9
Sin embargo si la parte izquierda es un array, la variable se hace igual a la lista que esta en la parte derecha:
  DB<9> @b = reverse @a
  DB<10> x @b
0  3
1  2
2  1

El Operador qw

Una abreviación muy cómoda para crear listas de cadenas la proporciona el operador qw. Una cadena formada por palabras separadas por espacios en blanco dentro de qw se descompone en la lista de sus palabras.

@a = qw(uno dos tres); # @a == ("uno","dos", "tres")
Observa que no se ponen comas entre las palabras. Si por error escribieras:
@a = qw(uno, dos, tres); # @a == ("uno,","dos,", "tres")
obtendrías comas extra en los elementos de la lista.

Otro ejemplo:

@week = qw(monday tuesday wednesday thursday friday saturday sunday);

Un Array No Inicializado es Vacío

Los escalares no inicializados tienen el valor undef. Sin embargo, las variables array no inicializadas tienen como valor la lista vacía (). Si se asigna undef a una variable de tipo array lo que se obtiene es una lista cuyo único elemento es undef:

@a = undef; # Equivalente a @a = ( undef );
if (@a) { ... } # Por tanto TRUE
El modo mas simple de evitar este tipo de problemas cuando se quiere limpiar una variable de tipo array es asignar explícitamente la lista vacía ():
@a = ();
if (@a) { ...}; # scalar(@a) == 0  es FALSE
También se puede usar el operador undef:
undef @a;
if (defined(@a)) { ... }; # FALSE

Es posible asignar undef a los elementos de un array:

$a[3] = undef;
O bien usando la lista vacía, como se hace en la siguiente sesión con el depurador:
  DB<1>  @a = 0..9
  DB<2> @a[1,5,7] = ()
  DB<3> p "@a"
0  2 3 4  6  8 9
  DB<4> p $#a
9
  DB<5> p scalar(@a)
10
  DB<6> $" = "," # separador de output de arrays
  DB<7> p "@a"
0,,2,3,4,,6,,8,9
  DB<8> @a[1..7] = ()
  DB<9> p "@a"
0,,,,,,,,8,9

Interpolación de arrays en cadenas

Al igual que los escalares, los valores de un array son interpolados en las cadenas de comillas dobles. Los elementos son automáticamente separados mediante el separador de elementos de un array que es el valor guardado en la variable especial $". Esta variable contiene un espacio por defecto.

  DB<1> @a = 0..9
  DB<2> print "@a 10\n"
0 1 2 3 4 5 6 7 8 9 10
  DB<3> $email = "casiano@ull.es"
  DB<4> print $email
casiano.es
  DB<5> $email = 'casiano@ull.es'
  DB<6> print $email
casiano@ull.es
  DB<7> $email = "casiano\@ull.es"
  DB<8> print $email
casiano@ull.es

Un único elemento de un array es reemplazado por su valor. La expresión que aparece como índice es evaluada como una expresión normal, como si estuviera fuera de una cadena:

  DB<1> @a = 0..9
  DB<2> $i = 2
  DB<3> $x = "$a[1]"
  DB<4> p $x
1
  DB<5> $x = "$a[$i-1]"
  DB<6> p $x
1
  DB<7> $i = "2*4"
  DB<8> $x = "$a[$i-1]"
  DB<9> p $x
1

Ejercicio 1.13.1   ¿Cuál es la explicación para la salida de p $x en el último ejemplo?

Ejercicio 1.13.2  

Dado la siguiente sesión con el depurador

nereida:~/perl/src> perl -de 0
main::(-e:1):   0
DB<1> @a = 1..5
DB<2> ($a[0], $a[1]) = undef
DB<3>  p "@a"
¿Cuál es la salida de la impresión que aparece al final de la secuencia de comandos?. ¿Se produce alguna dvertencia? ¿Que ocurre si se cambia la última línea por esta otra?

DB<3> no warnings; $" = ', '; print "@a"

Bucles sobre arrays: el Indice como alias

Una diferencia del bucle for de Perl con el de C es que el índice del bucle constituye un ''alias'' del correspondiente elemento del array, de modo que su modificación conlleva la modificación del elemento del array. Consideremos el siguiente código:
lhp@nereida:~/Lperl/src$ cat -n foreach1.pl
     1  #!/usr/bin/perl -w
     2  use strict;
     3
     4  my @list = 1..10;
     5  foreach my $n (@list) {
     6   $n *= 2;
     7  }
     8  print "@list\n";
su ejecución produce la siguiente salida:
lhp@nereida:~/Lperl/src$ foreach1.pl
2 4 6 8 10 12 14 16 18 20



Subsecciones
Casiano Rodríguez León
2009-10-04