Tablas (arrays)

El uso de tablas en Cobol es algo muy frecuente y por eso he decidido crear un apartado específico para hablar de ellas. En el capítulo de la DATA DIVISION, dentro de los manuales, podréis encontrar una explicación de cada comando o cláusula que veamos de aquí en adelante.

En primer lugar daremos una definición de ellas. Una tabla es un conjunto de elementos con un mismo tipo y longitud que se denominan con el mismo nombre y se diferencian por un subíndice. Todo lo que voy a explicar aquí, se hará desde lo más básico. Con un ejemplo lo vamos a ver mas claro:

    • Imaginamos que queremos tener la información de cuantas personas entran a un museo cada día de la semana. Si como máximo entran al día mas o menos 1.000 personas deberíamos declarar siete variables de la siguiente manera:

 

01  LUNES
01  MARTES
01  MIERCOLES
01  JUEVES
01  VIERNES
01  SABADO
01  DOMINGO
PIC 9(4).
PIC 9(4).
PIC 9(4).
PIC 9(4).
PIC 9(4).
PIC 9(4).
PIC 9(4).
    • Para introducir datos aquí podríamos hacer:

MOVE 200 TO LUNES.
MOVE 430 TO MARTES.
MOVE 136 TO MIERCOLES.
MOVE 525 TO JUEVES.
MOVE 380 TO VIERNES.
MOVE 1910 TO SABADO.
MOVE 2300 TO DOMINGO.
Fijaros que todas son del mismo tipo (numéricas) y del mismo tamaño (4), por lo tanto cumplen el requisito para crear una tabla, así que vamos a sustituir todo lo anterior haciendo uso de una tabla.

01  DIASEMANA.
02  VISITAS

PIC 9(4)  OCCURS 7 TIMES.

Ahora tendremos una única variable donde guardar los datos y se llamará VISITAS. Para introducir los datos lo haríamos refiriéndonos con un subíndice a cada uno de sus elementos, siete en este caso, porque siete son los días de la semana. Lo más lógico será respetar el orden de los días, es decir 1 para el Lunes, 2 para el Martes, etc …

MOVE 200 TO VISITAS (1).
MOVE 430 TO VISITAS (2).
MOVE 136 TO VISITAS (3).
MOVE 525 TO VISITAS (4).
MOVE 380 TO VISITAS (5).
MOVE 1910 TO VISITAS (6).
MOVE 2300 TO VISITAS (7).

El resultado es el mismo, pero solo hemos tenido que declarar una variable. Por supuesto el número que hace referencia al subíndice puede ser a su vez una variable, como veremos un poco mas abajo.

Cobol también posee la capacidad de crear una tabla y rellenarla a su vez utilizando la WORKING-STORAGE SECTION . Para ello primero declaramos los valores en una variable y gracias a la cláusula REDEFINES, hacemos que su valor se cargue en la tabla. Eso no quiere decir que su valor no se pueda cambiar, pero al iniciar el programa, la tabla contendrá esos valores. Para seguir con el ejemplo crearemos una con los días de la semana.

01  TABLADIAS.
02  FILLER
02  FILLER
02  FILLER
02  FILLER
02  FILLER
02  FILLER
02  FILLER
01  TABLADEDIAS
02  ELDIA

PIC X(10) VALUE «LUNES       «.
PIC X(10) VALUE «MARTES     «.
PIC X(10) VALUE «MIERCOLES «.
PIC X(10) VALUE «JUEVES      «.
PIC X(10) VALUE «VIERNES    «.
PIC X(10) VALUE «SABADO     «.
PIC X(10) VALUE «DOMINGO   «.
REDEFINES TABLADIAS.
PIC X(10) OCCURS 7 TIMES.

Ya tenemos cargada la tabla con los días de la semana respetando también el orden que hemos indicado anteriormente.

Ahora mostraremos las visitas de cada día utilizando las tablas y refiriéndonos a los elementos de la tabla con valores variables. Vamos a pedir que nos diga el día de la semana para el cual quiere saber las visitas que hubo:

WORKING-STORAGE SECTION.
01  DIA         PIC 9.
01  LVISITAS PIC Z.ZZ9.

PROCEDURE DIVISION.

PEDIR.
DISPLAY «INTRODUZCA DIA PARA VER SUS VISITAS»
LINE 4 COL 20.
ACCEPT DIA LINE 4 COL 50 PROMPT LOW.
IF DIA < 1 OR DIA > 7 GO PEDIR.
DISPLAY «EL » LINE 10 COL 20.
DISPLAY ELDIA (DIA) LINE 10 COL 23.
DISPLAY «HUBO » LINE 10 COL 33.
MOVE VISITAS (DIA) TO LVISITAS.
DISPLAY LVISITAS LINE 10 COL 38.
DISPLAY «VISITAS.» LINE 10 COL 44.

Al introducir, por ejemplo el valor 3 el resultado hubiera sido:

EL MIERCOLES HUBO  136 VISITAS.

VARIAS DIMENSIONES O NIVELES

Todas las que hemos visto son de una dimensión, pero se pueden definir de mas niveles y convertirlas en matrices. Por ejemplo ahora vamos a diferenciar en la tabla, además del número de visitas, si han sido hombres o mujeres, para ello creamos una nueva dimensión quedando la tabla de la siguiente manera:

01  DIASEMANA.
02  GENERO
03  VISITAS

OCCURS 2 TIMES.
PIC 9(4)  OCCURS 7 TIMES.

Como veis nuestra tabla contiene dos cláusulas OCCURS, con ello hemos conseguido crear una matriz de 2 x 7, ahora la variable VISITAS tendrá 14 elementos. Para dirigirnos a ellos utilizaremos dos subíndices. En nuestro caso al diferenciar el género, identificaremos con el valor 1 a los hombres y con el 2 a las mujeres. Veamos como rellenamos la tabla ahora:

MOVE 110 TO VISITAS (1, 1) MOVE 90 TO VISITAS (2, 1).
MOVE 130 TO VISITAS (1, 2) MOVE 300 TO VISITAS (2, 2).
MOVE 100 TO VISITAS (1, 3) MOVE 36 TO VISITAS (2, 3).
MOVE 250 TO VISITAS (1, 4) MOVE 225 TO VISITAS (2, 4).
MOVE 190 TO VISITAS (1, 5) MOVE 190 TO VISITAS (2, 5).
MOVE 1000 TO VISITAS (1, 6) MOVE 910 TO VISITAS (2, 6).
MOVE 1100 TO VISITAS (1, 7) MOVE 1200 TO VISITAS (2, 7).

Por supuesto al igual que antes los subíndices pueden ser sustituidos por variables. Por ejemplo, sabiendo los datos anteriores vamos a sumar todas las mujeres que entraron en la semana y todos los hombres y vamos a averiguar cual fue el día de mayor visitas y el día de menor asistencia.

WORKING-STORAGE SECTION.
01  DIA         PIC 9.
01  LVISITAS PIC Z.ZZ9.
01  MAYOR    PIC 9(4) VALUE 0.
01  MENOR    PIC 9(4) VALUE 9999.
01  DIAMAYOR PIC 9.
01  DIAMENOR PIC 9.
01  TOTAL    PIC 9(4).
01  HOMBRES PIC 9(4).
01  MUJERES PIC 9(4).

PROCEDURE DIVISION.

MOVE 0 TO DIA.
MIRAR.
ADD 1 TO DIA IF DIA > 7 GO FIN.
ADD VISITAS (1, DIA) TO HOMBRES.
ADD VISITAS (2, DIA) TO MUJERES.
COMPUTE TOTAL = VISITAS (1, DIA) + VISITAS (2, DIA).
IF TOTAL > MAYOR MOVE TOTAL TO MAYOR
MOVE DIA TO DIAMAYOR.
IF TOTAL < MENOR MOVE TOTAL TO MENOR
MOVE DIA TO DIAMENOR.
GO MIRAR.
FIN.
DISPLAY «TOTAL HOMBRES » LINE 10 COL 10 ERASE.
MOVE HOMBRES TO LVISITAS.
DISPLAY LVISITAS LINE 10 COL 35.

DISPLAY «TOTAL MUJERES » LINE 11 COL 10.
MOVE MUJERES TO LVISITAS.
DISPLAY LVISITAS LINE 11 COL 35.

DISPLAY «———————————-»
LINE 12 COL 10.
DISPLAY «TOTAL VISITAS » LINE 13 COL 10.
COMPUTE LVISITAS = HOMBRES + MUJERES.
DISPLAY LVISITAS LINE 13 COL 35.
DISPLAY «———————————-»
LINE 14 COL 10.

DISPLAY «DIA MAYOR » LINE 15 COL 10.
DISPLAY TSEM (DIAMAYOR) LINE 15 COL 22.
MOVE MAYOR TO LVISITAS.
DISPLAY LVISITAS LINE 15 COL 35.

DISPLAY «DIA MENOR» LINE 17 COL 10.
DISPLAY TSEM (DIAMENOR) LINE 17 COL 22.
MOVE MENOR TO LVISITAS.
DISPLAY LVISITAS LINE 17 COL 35.
ACCEPT OP LINE 20.


LLENANDO TABLAS

Ahora imaginamos que los datos de la tabla de visitas, en vez de asignarlos con un MOVE como hemos hecho en los ejemplos anteriores, los vamos a pedir mediante ACCEPT en un programa. Vamos a hacer un pequeño programa para que veais como quedaría:

WORKING-STORAGE SECTION.
01  DIASEMANA.
02  GENERO       OCCURS 2 TIMES.
03  VISITA   PIC 9(4) OCCURS 7 TIMES.
01  SUB1       PIC 9.
01  SUB2       PIC 9.
01  OP          PIC X.
01  LGENERO  PIC X(7).

PROCEDURE DIVISION.
INICIO.
DISPLAY «CAPTURA DE DATOS» LINE 2 COL 10 ERASE.
MOVE 0 TO SUB1 SUB2.
METER.
ADD 1 TO SUB2 IF SUB2 > 7 GO FIN.
MOVE 0 TO SUB1.
METER1.
ADD 1 TO SUB1 IF SUB1 > 2 GO METER.
IF SUB1 = 1 MOVE «HOMBRES» TO LGENERO ELSE
MOVE «MUJERES» TO LGENERO.
DISPLAY «VISITAS DE » LINE 10 COL 10.
DISPLAY LGENERO LINE 10 COL 21.
DISPLAY «EL DIA» LINE 10 COL 29.
DISPLAY TSEM (SUB2) LINE 10 COL 37.
ACCEPT VISITAS (SUB1, SUB2) LINE 10 COL 50.
GO METER1.
FIN.
DISPLAY «PROCESO DE CAPTURA FINALIZADO»
LINE 20 COL 20.
ACCEPT OP LINE 20 COL 1.

Ahora podríamos incluir el código anterior y que nos calcule el día de mayor y menor visitas y la suma por géneros.BUSCANDO EN TABLAS

Para buscar en las tablas existe un comando propio llamado SEARCH, que veremos al final del capítulo, pero ahora vamos a hacer una busqueda por subíndices normal para encontrar alguno o varios elementos que cumplan una determinada condición. Por ejemplo, siguiendo con nuestra tabla (es un poco pequeña, pero podría ser todo lo grande que quisieramos, siempre que no desbordaramos la memoria del ordenador o la capacidad del compilador), vamos a buscar los días en los que la afluencia es mayor de 1.000 personas, para saber si es necesario contratar a mas personal para esos días.

Pero para complicar un poco mas el asunto, vamos a meter dichos días en otra tabla y así aprendemos a trabajar con  mas de una tabla a la vez.

WORKING-STORAGE SECTION.
01  DIASEMANA.
02  GENERO       OCCURS 2 TIMES.
03  VISITA   PIC 9(4) OCCURS 7 TIMES.
01  TABLA1000.
02  ELEMENTOS1000 OCCURS 7 TIMES.
02  DIA1000       PIC 9.
02  VISITAS1000 PIC 9(4).
01  SUB1       PIC 9.
01  SUB2       PIC 9.
01  SUB3       PIC 9.
01  TOPE       PIC 9.
01  OP          PIC X.
01  LGENERO  PIC X(7).

PROCEDURE DIVISION.
INICIO.
DISPLAY «BUSCANDO DIAS DE MAS DE 1000 VISITAS»
LINE 2 COL 10 ERASE.
MOVE 0 TO SUB1 SUB2.
BUSCAR.
ADD 1 TO SUB1 IF SUB1 > 7 GO MOSTRAR.
COMPUTE TOTAL = VISITAS (1, SUB1) + VISITAS (2,SUB1).
IF TOTAL > 1000
ADD 1 TO SUB2 MOVE SUB1 TO DIA1000 (SUB2)
MOVE TOTAL TO VISITAS1000 (SUB2).
GO BUSCAR.
MOSTRAR.
MOVE SUB2 TO TOPE MOVE 0 TO SUB2.
MOSTRAR1.
ADD 1 TO SUB2 IF SUB2 > TOPE GO FIN.
DISPLAY «EL » LINE 10 COL 29.
MOVE DIA1000 (SUB2) TO SUB3.
DISPLAY TSEM (SUB3) LINE 10 COL 37.
DISPLAY VISITAS1000 (SUB2) LINE 10 COL 50.
GO MOSTRAR1.
FIN.
DISPLAY «PROCESO DE BUSQUEDA FINALIZADO»
LINE 20 COL 20.
ACCEPT OP LINE 20 COL 1.



MAS TABLAS

Voy a poner algunos ejemplos de definición de tablas mas complicados que los expuestos en los ejemplos.

01  TABLA.
02  TRABAJADORES
03  NOMBRE
03  NIF
03  SALARIO
05   BRUTO
05   NETO
05   GASTOS
07   GASTO

OCCURS 100 TIMES.
PIC X(30).
PIC X(10).
OCCURS 12 TIMES.
PIC S9(8).
PIC S9(8).
OCCURS 10 TIMES.
PIC S9(8).

 

    • Los valores para esta tabla sería:

 

        • 100 TRABAJADORES de los que tendríamos NOMBRE y NIF referidos como NOMBRE (X) y NIF (X).
        • A su vez tendríamos un salario por mes (12). Descritos con dos variables BRUTO Y NETO a los que nos referiríamos como BRUTO (CLIENTE, MES) y NETO (CLIENTE, MES).
        • Y también 10 tipos de gastos por cliente y mes referidos como GASTO (CLIENTE, MES, TIPO).

Como véis se puede complicar cuanto se quiera:

– Para saber el nombre del trabajador número 49: DISPLAY NOMBRE (49).
– Para saber el Nif del trabajador 20: DISPLAY NIF (20).
– Para saber el bruto de Mayo del trabajador 15: DISPLAY BRUTO (15, 5).
– Para saber el neto del trabajador 90 del mes de Noviembre:
DISPLAY NETO (90, 11).
– Para saber el gasto número 3 del mes de Febrero del trabajador 10:
DISPLAY GASTO (10, 2, 3).


TABLAS DE LONGITUD VARIABLE.

Podemos definir también una tabla con un número de elementos variable, dependiendo del valor de una variable. Su definición sería así:

01  MES
01  SEMANA.
02 VISTAS
PIC 99.

PIC 9(4) OCCURS 28 TO 31 DEPENDING OF MES.


INDEXACION.

Además podemos asignar una variable por la cual nos referiremos a cada elemento, esto se hace añadiendo a la línea que contiene la cláusula OCCURS, la palabra INDEXED seguida del nombre de variable que deseemos. La ventaja es que no hay que definirla en la WORKING. En nuestro ejemplo le pondremos de nombre DIA y quedaría asi:

01  DIASEMANA.
02  VISITAS

PIC 9(4)  OCCURS 7 TIMES INDEXED DIA.

La gran ventaja de utilizar este método, es que no hay que definir esa variable, no hay que controlar los rangos y además el valor no se alterará ya que no utilizaremos esa variable para nada mas.

Para dar valor a éste tipo de variables hay que utilizar la sentencia SET, ya que no se pueden utilizar los comandos normales ni declaraciones aritméticas, con el siguiente formato:

SET DIA TO 1. Da el valor 1 al índice 1.
SET DIA UP 3. Suma 3 al valor del índice.
SET DIA DOWN 2. Resta 1 al valor del índice 2.

Además también utilizamos la indexación para hacer busquedas en las tablas mediante la sentencia SEARCH.

Antes hemos visto como buscar utilizando un contador y unos IF para verificar lo que buscamos. Pero Cobol tiene una sentencia específica para buscar un valor en una tabla. Esta sentencia se llama SEARCH.

Si imaginamos una tabla de trabajadores y queremos encontrar la posición en concreto que ocupa uno o saber si existe en la tabla haremos lo siguiente:

01  TABLA.
02  TRABAJADORES   OCCURS 100 TIMES
INDEXED BY SUB1.
03  NOMBRE        PIC X(30).
03  NIF              PIC X(10).

PROCEDURE DIVISION.

BUSCAR.
SET SUB1 TO 1.
SEARCH ELEMENTOS AT END GO NOEXIS
WHEN NOMBRE (SUB1) = «ANDRES MONTES»
GO EXISTE.
NOEXIS.
DISPLAY «TRABAJADOR INEXISTENTE» LINE 1.
GO FIN.
EXIS.
DISPLAY «EL NIF DEL TRABAJADOR ES .» LINE 2.
DISPLAY NIF (SUB1) LINE 2 COL 30.

Primero inicializamos la variable de indexación para que empiece por el elemento 1, pero podiamos haber escogido el valor que quisieramos, si le hubieramos dado uno fuera de rango, simplemente la instrucción hubiera saltado al párrafo NOEXIS indicado en el AT END.

La sentencia SEARCH a continuación crea un bucle hasta que se cumpla la condición dada. Si no la encuentra realiza la instrucción que haya despues de AT END. Podemos poner todas las condiciones con WHEN que queramos y se irán ejecutanto en el orden en que se hayan puesto.

También existe la posibilidad de hacer una busqueda total de la tabla con la cláusula ALL en la sentencia SEARCH, se denomina busqueda binaria.

Esta fórmula es mas utilizada en tablas mas grandes. Aquí no hay que preocuparse por el valor del subíndice, el comando se encarga de todo. Pero solo podremos poner una condición WHEN y además el elemento de la tabla por el que se busque debe de estar clasificado y especificado en la WORKING con la opción ASCENDING o DESCENDING. Veamos un ejemplo:

01  TABLA.
02  TRABAJADORES   OCCURS 100 TIMES
ASCENDING KEY NOMBRE
INDEXED BY SUB1.
03  NOMBRE        PIC X(30).
03  NIF              PIC X(10).

PROCEDURE DIVISION.

BUSCAR.
SEARCH ALL ELEMENTOS AT END GO NOEXIS
WHEN NOMBRE (SUB1) = «ANDRES MONTES»
GO EXISTE.
NOEXIS.
DISPLAY «TRABAJADOR INEXISTENTE» LINE 1.
GO FIN.
EXIS.
DISPLAY «EL NIF DEL TRABAJADOR ES .» LINE 2.
DISPLAY NIF (SUB1) LINE 2 COL 30.

La diferencia en cuanto a programación es mínima, pero el sistema tarda menos en la busqueda y no tenemos que tener en cuenta el inicializar el contador. Por el contrario es necesario tener ordenada nuestra tabla y esto a veces no sea tan rentable.

Obviamente cada una de éstas formas de buscar en Tablas son opciones que ofrece el lenguaje Cobol. Supongo que como en todo lo que se buscaba al principio era limitar los tiempos de respuesta, puesto que las máquinas eran muy pequeñas y tenían pocos rendimientos, de ahí que ésta orden se haya visto inalterada desde el principio.

Cada uno puede utilizar la forma que mejor se le de, la que mejor entienda o la que mejor haga su cometido.

Seguramente se podría haber hablado mucho mas de tablas, pero lo importante y lo que pretendía con éste capítulo, era que comprendiérais el porque de una tabla y su uso mas frecuente.