Un array es una tabla de varios valores, llamados
elementos. Los elementos de un array se distinguen por sus índices. Los índices
pueden ser tanto cadenas como números. Cada array tiene un nombre, que es similar
al nombre de una variable, pero no debe estar siendo usado como nombre de variable
en un mismo programa awk.
El lenguaje awk tiene arrays de una dimensión para almacenar grupos de cadenas o números
relacionados.
Todos los arrays en awk deben tener un nombre. Los nombres de los arrays presentan la misma sintáxis
que los nombres de variables; cualquier nombre de variable válido será un nombre
válido para un array. Pero no se puede usar un mismo nombre para un array y
una variable en un mismo programa awk.
Los arrays en awk se asemejan superficialmente a los arrays en otros lenguajes de programación;
pero existen diferencias fundamentales. En awk, no es necesario especificar el tamaño de un array antes de empezar a
usarlo. Lo que és más, en awk, cualquier número o incluso cadena podría ser usado como un índice de
array.
En la mayoría de otros lenguajes, tienes que declarar
un array y especificar cuantos elementos o componentes tiene. En dichos lenguajes,
la declaración causa la reserva de un bloque de memoria contiguo para tantos
elementos como se hayan especificado. Un índice para esos arrays debe ser un
entero positivo, por ejemplo, el índice 0 especifica el primer elemento del
array, el cual se encuentra realmente almacenado al principio del bloque de
memoria reservado. Índice 1 especifica el segundo elemento, el cual está almacenado
en la memoria justo a continuación del primer elemento, y así sucesivamente.
No es posible añadir más elementos al array, porque la reserva de memoria ya
se ha realizado para el número de elementos que se declaró inicialmente que
iba a tener el array.
Un array contiguo de cuatro elementos podría presentar
una forma similar a la siguiente, conceptualmente, si los valores de los elementos
son 8, foo, y 30:
+---------+---------+--------+---------+
¦ 8 ¦ "foo" ¦ "" ¦ 30 ¦ value
+---------+---------+--------+---------+
0 1 2 3 index
Solamente los valores son almacenados; los índices
son implícitos por el orden de los valores. 8 es el valor del índice 0, porque
8 aparece en la posición con 0 elementos antes de él.
Los arrays en awk son diferentes: son asociativos. Esto significa que cada array
es una colección de pares: un índice, y su valor de elemento de array correspondiente:
Elemento 4 Valor 30
Elemento 2 Valor "foo"
Elemento 1 Valor 8
Elemento 3 Valor ""
Hemos mostrado los pares en un orden aleatorio porque
el orden no tiene ningún significado.
Una ventaja de un array asociativo es que puedes añadir
nuevas parejas en cualquier momento. Por ejemplo, supón que añadimos a ese array
un elemento décimo cuyo valor es número diez. El resultado es este:
Elemento 10 Valor "número diez"
Elemento 4 Valor 30
Elemento 2 Valor "foo"
Elemento 1 Valor 8
Elemento 3 Valor ""
Ahora el array es disperso (algunos índices no aparecen):
tiene los elementos 4 y 10, pero no tiene los elementos 5, 6, 7, 8, y 9.
Otra consecuencia de los arrays asociativos es que
los índices no tienen por qué ser enteros positivos. Cualquier número, o incluso
una cadena, puede ser un índice de un array. Por ejemplo, aquí está un array
el cual traduce palabras de Inglés a Francés:
Elemento "dog" Valor "chien"
Elemento "cat" Valor "chat"
Elemento "one" Valor "un"
Elemento 1 Valor "un"
Aquí nosotros decidimos traducir el número 1 en ambas
formas, la forma numérica y alfabética, lo que supone un ejemplo claro de que
un array puede tener ambos números y cadenas como índices.
Cuando awk crea un array para ti, por ejemplo con la función implícita split
(Ver la sección
Funciones
Implícitas (Built-in) para Manipulación de Cadenas),
esos índices del array son enteros consecutivos que comienzan con el 1.
La forma principal de usar un array es referirse a
uno de sus elementos. Una referencia a un array es una expresión que presenta
la siguiente forma:
array[índice]
Aquí array es el nombre de un array. La expresión
índice es el índice del elemento del array que tú quieres.
El valor de la referencia al array es el valor actual
del elemento del array. Por ejemplo, foo[4,3] es una expresión para el elemento
cuyo índice es 4,3 del array foo.
Si referencias un elemento de array en el que no se
ha grabado ningún valor, el valor devuelto por esta referencia es , la cadena
nula. Esto incluye elementos a los cuales no les has asignado un valor, y los
elementos que han sido borrados (Ver la sección La
Sentencia delete). Esta referencia automáticamente crea dicho
elemento de array, con la cadena nula como su valor. (en algunos casos esto
es un incoveniente ya que supone un desperdicio de memoria por parte de awk).
Puedes averigurar si existe un elemento en un array
para un determinado índice con la expresión:
índice in array
Esta expresión chequea si existe o no el índice especificado,
sin el efecto lateral de crear dicho elemento si no está presente. La expresión
tendrá el valor de 1 (verdadero) si array[índice] existe, y 0 (falso) si no
existe.
Por ejemplo, para chequear si el array frequencies
contiene el índice 2, podrías escribir esta sentencia:
if ("2" in frequencies) print "Subscript \"2\" is present."
Señalar que esto no es un chequeo de si el array frequencies contiene o no un elemento cuyo valor es 2. (No hay forma de hacer esto,
excepto escaneando todos los elementos). También, esta sentencia no crea
frequencies[2], mientras que la siguiente sentencia (incorrecta) alternativa si lo haría:
if (frequencies["2"] != "") print "Subscript \"2\" is present."
Los elementos de un array son valoresi: les
pueden ser asignados valores del mismo modo que a las variables awk.
array[subíndice] = valor
Aquí array es el nombre de tu array. La expresión
subíndice es el índice del elemento del array al que le quieres asignar
un valor. La expresión valor es el valor que le estás asignando al elemento
del array.
El siguiente programa toma una lista de líneas, cada
una comenzando con un número de línea, y las imprime en orden del número de
línea. Los números de línea no están en orden. Este programa ordena las líneas
creando un array usando los números como subíndices. Después imprime las líneas
ordenadas por sus números. Es un programa muy simple, y se confunde si encuenta
números repetidos, huecos o líneas que no comiencen con un número.
{
if ($1 > max)
max = $1
arr[$1] = $0
}
END {
for (x = 1; x <= max; x++)
print arr[x]
}
La primera regla guarda el número de línea más alto
leído hasta el momento; también guarda cada línea en el array arr, en un índice que
es el número de línea.
La segunda regla se ejecuta después de que se hayan
leído toda la entrada, para imprimir todas las líneas. Cuando este programa
se ejecuta con la siguiente entrada:
5 I am the Five man
2 Who are you? The new number two!
4 . . . And four on the floor
1 Who is number one?
3 I three you.
su salida es la siguiente:
1 Who is number one?
2 Who are you? The new number two!
3 I three you.
4 . . . And four on the floor
5 I am the Five man
Si se repite un número de línea, la
última línea con dicho número repetido es la que permanece.
Los huecos en números de línea pueden ser manejados con una fácil mejora a la regla END del programa:
END {
for (x = 1; x <= max; x++)
if (x in arr)
print arr[x]
}
En programas que utilizan arrays, a menudo necesitas
un bucle que se ejecute para cada elemento de un array. En otros lenguajes,
donde los arrays son contíguos y los índices están limitados a enteros positivos,
esto es fácil: el índice mayor es una unidad menor que el tamaño del array,
y puedes encontrar todos los índices válidos recorriendo desde 0 hasta dicho
valor. Esta técnica no servirá en awk, ya que cualquier número o cadena podría ser un índice de array. Así
que awk tiene un tipo especial de sentencia for para
el recorrido de arrays:
for (variable in array)
cuerpo
Esto hace que se ejecute cuerpo una vez para
cada valor diferente que su programa haya usado previamente como un índice en
array, con la variable variable que recibe el valor de dicho índice.
Aquí tienes un programa que utiliza esta forma de
la sentencia for. La primera regla escanea los registros de entrada y
anota que palabras aparecen (al menos una vez) en la entrada, almacenando un
1 en el array, usando la palabra en cuestión como índice. La segunda regla escanea
los elementos del array used para encontrar todas las palabras distintas
que aparecen en la entrada. Imprime todas las palabras que son de más de 10
caracteres y también imprime el número de veces que aparecen dichas palabras
en el fichero de entrada. Ver la sección
11.
Funciones Implícitas (Built-in)
, para más información de la función
implícita length.
# Record a 1 for each word that is used at least once.
{
for (i = 1; i <= NF; i++)
used[$i] = 1
}
# Find number of distinct words more than 10 characters long.
END {
num_long_words = 0
for (x in used)
if (length(x) > 10) {
++num_long_words
print x
}
print num_long_words, "words longer than 10 characters"
}
Ver la sección
16.
Programa Ejemplo, para ver un ejemplo más detallado de este tipo.
El orden en el cual esta sentencia accede a los elementos
del array es determinado por la disposición interna de los elementos del array
dentro de awk y no puede ser controlada ni cambiada. Esto puede llevar
a problemas si se añaden nuevos elementos al array mediante sentencias
en cuerpo, no se puede predecir si el bucle for recorrerá o no
estos nuevos elementos. De forma similar, cambiando variable dentro del
bucle podría producir resultados extraños.
Puedes eliminar un elemento individual de un array utilizando
la sentencia delete:
delete array[index]
Cuando un elemento de array es eliminado, es como sí nunca lo
hubieses referenciado y nunca le hubieses dado un valor. Cualquier valor que
tuviese el elemento del array eliminado nunca podrá ser obtenido.
Aquí está un ejemplo de la eliminación de elementos en un array:
for (i in frequencies)
delete frequencies[i]
El ejemplo elimina todos los elementos del array frequencies.
Si eliminas un elemento, una sentencia for realizada a continuación
para escanear el array no te devolverá dicho elemento y el operador in para
chequear la existencia de un elemento te devolverá un 0:
delete foo[4]
if (4 in foo)
print "Esto nunca será impreso"
Un array multidimensional es un array en el cual un
elemento es identificado por una secuencia de índices, no por un único índice.
Por ejemplo, un array bidimensional requiere dos índices. La forma normal (en
la mayoría de los lenguajes incluyendo awk) para referirse a un elemento de un array bidimensional llamado grid es mediante grid[x,y].
Los arrays multidimensionales son soportados en awk mediante la concatenación de índices en una
cadena. Lo que ocurre es que awk
convierte los índices en cadenas (Ver la sección
Conversiones de Cadenas y
Números
) y los concatena juntos, con un separador entre ellos.
Esto crea una única cadena que describe el valor de los índices separados. La
cadena combinada es usada como un índice único (normal) en un array unidimensional
normal. El separador usado es el valor de la variable implícita SUBSEP.
Por ejemplo, supón que evaluamos la expresión foo[5,12]=”valor” donde el valor de SUBSEP es @. Los números 5 y 12 están concatenados con una coma entre ellos,
produciendo 5@12; por lo que, el elemento del array foo[5@12]
es fijado a valor.
Una vez que el valor del elemento es almacenado, awk no tiene forma de saber si se almacenó como
un índice único o como una secuencia de índices. Las dos expresiones foo[5,12] y foo[5 SUBSEP 12] siempre tienen el mismo valor. El valor por defecto de SUBSEP es actualmente la cadena \034, que contiene un carácter no imprimible que es poco probable que aparezca
en un programa awk o en los datos de entrada.
La falta de utilidad de elegir un carácter poco probable
viene del hecho de que los valores de índices que contienen una cadena que concuerde
con SUBSEP llevan a cadenas combinadas que son ambiguas. Supón que SUBSEP fuese
@; entonces foo[a@b, c] y foo[a, b@c] serían indistinguibles porque ambas serían realmente almacenadas como
foo[a@b@c]. Debido a que SUBSEP es \034, tales confusiones pueden ocurrir realmente solo cuando un índice contiene
el carácter con código ASCII
034, lo cual es muy raro.
Puedes chequear si una secuencia de índice en particular
existe en un array multidimensional con el mismo operador in utilizado para arrays de una sola dimensión.
En lugar de un índice simple como el operando izquierdo, escribe la secuencia
completa de índices separados por comas, en paréntesis:
(subscript1, subscript2, ...) in array
El siguiente ejemplo trata su entrada
como un array bidimensional de campos; rota este array 90 grados en el sentido
de las agujas del reloj e imprime el resultado. Asume que todas las líneas tienen
el mismo número de elementos.
awk '{
if (max_nf < NF)
max_nf = NF
max_nr = NR
for (x = 1; x <= NF; x++)
vector[x, NR] = $x
}
END {
for (x = 1; x <= max_nf; x++) {
for (y = max_nr; y >= 1; --y)
printf("%s ", vector[x, y])
printf("\n")
}
}'
Cuando se le pasa la siguiente entrada:
1 2 3 4 5 6
2 3 4 5 6 1
3 4 5 6 1 2
4 5 6 1 2 3
produce la siguiente salida:
4 3 2 1
5 4 3 2
6 5 4 3
1 6 5 4
2 1 6 5
3 2 1 6
No existe ninguna sentencia especial for que escanee un array multidimensional; no puede
existir ninguna, porque en realidad no hay arrays o elementos multidimensionales;
existe solo una forma de acceso a un array multidimensional.
Sin embargo, si tu programa tiene un array que es
siempre accedido como multidimensional, puedes obtener el efecto de escanearlo
combinando la sentencia de escaneo for (Ver la sección
Recorrido de todos los elementos
de un Array
) con la función implícita
split
(Ver la sección
Funciones Implícitas (Built-in) para Manipulación de Cadenas).
Funciona de la siguiente manera:
for (indice_combinado in array) {
split(índice_combinado, array_índices, SUBSEP)
...
}
Esto encuentra cada concatenación, índice combinado
del array, y lo divide en índices individuales separándolos por las posiciones
donde aparezca el valor de SUBSEP. Los índices separados se convierten en los elementos del array array_índices.
Por lo que, supón que has almacenado previamente en
array[1,”foo”]; entonces un elemento con índice
"1\034foo"
existe en el array. (Recuerda que el valor por defecto de SUBSEP
contiene el carácter con código 034). Antes o después, la sentencia for
encontrará ese índice y realizará una iteración en la cual índice_combinado tomará el valor "1\034foo". Entonces la función split
se llamará con los siguientes parámetros:
split("1\034foo", array_índices, "\034")
El resultado de esto es fijar el valor
1
para array_índices[1]
y el valor foo para array_índices[2]. Por lo que, la secuencia original
de índices separados ha sido recuperada.
Manual |