Está en la página 1de 18

Curso 2014/15

FUNDAMENTOS DE PROGRAMACIÓN Versión: 1.0.3

Tema 5. Tratamientos Secuenciales Básicos


Autor: Miguel Toro Bonilla
Revisión: profesores de la asignatura
Tiempo estimado: 6 horas

1. Introducción ................................................................................................................................................ 2
2. Fuentes de datos básicas y mecanismos para la generación de los datos del agregado ......................... 5
2.1 Arrays .................................................................................................................................................. 5
2.2 Secuencias Numéricas......................................................................................................................... 5
2.3 El tipo Iterable ..................................................................................................................................... 6
3. Acumuladores ............................................................................................................................................. 6
3.1 Acumuladores con una función salir que devuelve siempre falso..................................................... 6
3.1.1 Suma (sum).................................................................................................................................. 6
3.1.2 Producto (multiply) ..................................................................................................................... 7
3.1.3 Contador (count) ......................................................................................................................... 8
3.1.4 Acumula Lista (toList) ................................................................................................................. 8
3.1.5 Acumula Conjunto (toSet)........................................................................................................... 8
3.1.6 Acumula Array (toArray) ............................................................................................................ 9
3.2 Acumulador que no acumula............................................................................................................ 10
3.2.1 Ejecuta Para Todo ..................................................................................................................... 10
3.3 Acumuladores con función salir ....................................................................................................... 10
3.3.1 Para Todo (all) ........................................................................................................................... 10
3.3.2 Existe (any) ................................................................................................................................ 11
3.3.3 Busca Primero (first) ................................................................................................................. 11
3.3.4 Posición del Primero (index) ..................................................................................................... 12
3.4 Esquemas que dependen de órdenes ............................................................................................... 13
3.4.1 Máximo (max) ........................................................................................................................... 13
3.4.2 Mínimo (min)............................................................................................................................. 14
4. Ejemplos y metodología de trabajo ......................................................................................................... 14
5. Ejercicios.................................................................................................................................................... 17
2 Introducción a la Programación

1. Introducción

Al tratar con agregados de datos (listas, conjuntos, arrays, cadenas de caracteres, secuencias de valores y, en
general, todos los tipos que implementen la interfaz Iterable<E> o Stream<E>) es muy común buscar
información sobre cantidades agregadas: máximos o mínimos, posiciones de elementos en el agregado, etc.
Estos tratamientos se repiten continuamente. Nuestro objetivo es estudiar estos tratamientos sobre
agregados de datos y hacer un catálogo lo más extenso posible de los mismos y, a ser posible,
implementarlos en métodos que puedan ser reutilizados. En este tema se estudiará un primer bloque de
tratamientos secuenciales, que más tarde ampliaremos con otro bloque.

Java 8 ya proporciona, de forma muy eficiente y clara, la mayoría de estos métodos asociados al tipo de
datos Stream<E>. El objetivo de este capítulo no es estudiar los métodos de Stream<E>, sino desarrollar las
ideas en las que se basan para poder implementarlas en lenguajes que no dispongan de ese tipo de datos o,
simplemente, para comprender su funcionamiento interno.

Dado un agregado de objetos podemos plantearnos preguntas del tipo:

 ¿cuánto vale la suma de una expresión que se aplica sobre los objetos del agregado?
 ¿y el producto de los que verifican una propiedad?
 ¿existe algún objeto que verifique una determinada condición?
 ¿cuáles son los objetos que cumplen una determinada propiedad?
 ¿cuál es el valor más grande de los que cumplen una condición?
 según un orden dado, ¿cuál es mayor elemento de los que cumplen una condición?
 actualiza todos los objetos que cumplen una condición
 almacena en una lista los objetos que cumplen una condición
 etc.

Cada una de esas preguntas y otras similares pueden ser respondidas con métodos que tienen una
estructura común.

Un ejemplo de este tipo de pregunta es: ¿Cómo se calcula la suma de los cuadrados de los números enteros
contenidos en una lista de Enteros?

Como el agregado es una lista usamos un for extendido para recorrerla. El código lo concretamos en un
método que tomando una lista como parámetro, devuelve el resultado esperado, un número entero.

Ejemplo 1. Método que calcula la suma de los cuadrados de los enteros contenidos en una lista

public static Integer sumaCuadrados(List<Integer> v){


Integer suma=0;
for (Integer e: v){
suma = suma + e*e;
}
return suma;
}
5. Tratamientos secuenciales básicos
3

Igualmente podemos preguntarnos por la suma de los cuadrados de todos los enteros que van desde un
entero dado, a, hasta otro b (mayor que a) en pasos de c (positivos). Por ejemplo la secuencia 10, 12, 14, 16,
18, 20 sería especificada por a=10, b=20, c=2.

Para generar la secuencia de números usamos un for clásico. El método resultante es:

Ejemplo 2. Suma de los cuadrados de un número en un intervalo

public static Integer sumaCuadradosIntervalo(Integer a, Integer b,


Integer c) {
if(!(b>a && c>0))
throw new IllegalArgumentException();

Integer suma=0;
for (Integer e=a; e<=b; e=e+c) {
suma = suma + e*e;
}
return suma;
}

El método anterior eleva una excepción si los parámetros recibidos no cumplen lo especificado (que b sea
mayor que a y que c sea mayor que cero). Salvando la comprobación de la idoneidad de los parámetros
ambos métodos tienen, como vemos, la misma estructura.

Veamos ahora un problema más general: sumar los cuadrados de los enteros contenidos en una lista que
son múltiplos de 3.

Ejemplo 3. Método que suma los cuadrados de los enteros de una lista que son múltiplos de 3.

public static Integer sumaCuadradosMultiplos3(List<Integer> v) {

Integer suma=0;
for(Integer e: v){
if(Enteros.esMultiplo(e,3)) {
suma = suma + e*e;
}
}
return suma;
}

También se puede aplicar este esquema general en la secuencia definida por a, b, c. Es decir, los enteros
desde a hasta b con incrementos de c.

Ejemplo 4. Método que suma los cuadrados de los enteros de una secuencia que son múltiplos de 3.

public static Integer sumaCuadradosIntervaloMultiplos3(Integer a, Integer b,


Integer c) {
if(!(b>a && c>0))
throw new IllegalArgumentException();

Integer suma=0;
for (Integer e=a; e<=b; e=e+c) {
if(Enteros.esMultiplo(e,3)){
4 Introducción a la Programación

suma = suma + e*e;


}
}
return suma;
}

En estos métodos aparece una estructura que se repetirá. Esta estructura tiene varios elementos a destacar:
una fuente de datos y un mecanismo de recorrido de los datos, un acumulador, un filtro, una
transformación, y un criterio de parada.

 Fuente de datos: Es el origen de los datos. Puede ser una variable de un tipo agregado de datos (Set,
List, …), un agregado virtual de datos (los enteros pares entre los valores a y b, …), una secuencia
descrita por un primer elemento y el siguiente de uno dado, etc. El tipo del agregado será Ag y
asumimos que los elementos que lo componen son de tipo E.
 Mecanismo de generación de los datos: La forma concreta de generar, uno tras otro, los datos del
agregado. Por ejemplo, los elementos de una lista se pueden recorrer hacia arriba o hacia abajo. Una
opción para implementar este recorrido es generar los índices de la lista con un for y,
posteriormente, obtener los contenidos de las casillas. Otro ejemplo sería la generación de los
enteros pares entre a y b mediante un for.
 Acumulador: Es una variable que acumula el resultado calculado hasta ese momento. Un
acumulador es una variable que es de un tipo A que hay que especificar. Necesita un valor inicial y
una función acumula(a,e) capaz de acumular el elemento e en el acumulador a. Dependiendo de que
el tipo A sea mutable o inmutable la función acumula tendrá un diseño u otro. Un acumulador
concreto es suma. En ese caso A es un tipo numérico, se inicializa a cero y la función acumula es de
la forma a = a+e. Algunos acumuladores tienen, además, un criterio de parada.
Un criterio de parada es una expresión lógica, que podemos denominar salir(a), que depende del
valor del acumulador y nos indica si el valor actual del acumulador es ya el valor acumulado final y,
por lo tanto, salimos del bucle de la iteración.
 Filtro: Es una expresión lógica sin efectos laterales que nos sirve para escoger los elementos del
agregado sobre los que vamos a hacer el cálculo. El filtro lo concretaremos en una expresión lógica
que llamaremos filtra(e). En los ejemplos 3 y 4 el filtro es la expresión Enteros.esMultiplo(e,3).
 Transformación: Es una expresión que a partir de cada objeto del agregado calcula otro valor que es
el que queremos acumular. La transformación la concretaremos en una expresión que llamaremos
transforma(e) que puede devolver un tipo T distinto a E. En los ejemplos 1, 2, 3 y 4 la transformación
es la expresión e*e.
 Resultado: Una función que a partir del valor del acumulador devuelve el resultado buscado. La
concretaremos en una función que llamaremos resultado(a) que devolverá un valor del tipo R.

Con estas ideas los esquemas iterativos cuyo objetivo es acumular un valor a partir de un agregado tienen la
siguiente forma:

R esquemaSecuencial(Ag ag) {
A a = valor inicial;
Para cada e en ag {
if (filtra(e)) {
T e1 = transforma(e);
acumula(a,e1);
5. Tratamientos secuenciales básicos
5

}
if(salir(a)) break;
}
return resultado(a);
}

En el esquema anterior vemos entonces los elementos: acumulador, fuente de datos y mecanismo concreto
para ir recorriendo los datos de la fuente de datos.

Como vemos, el acumulador es una variable de tipo A, y tiene un conjunto de operaciones asociadas:
 acumula(a,e)
 salir(a)
 resultado(a)
 valorinicial(a)

Dependiendo de que el tipo A sea mutable o inmutable las funciones anteriores pueden tomar una forma u
otra. La funciones anteriores se pueden considerar separadas unas de otras, si estamos programando en un
lenguaje como C, o considerarlas asociadas al tipo A si usamos un lenguaje como Java u otro orientado a
objetos.

En este capítulo nos concentraremos en los esquemas secuenciales y los detalles de su implementación en
diferentes tipos de lenguajes.

2. Fuentes de datos básicas y mecanismos para la generación de los datos del agregado

Las fuentes de datos que veremos en este tema son: los arrays, las secuencias numéricas (de enteros o
reales), las listas, conjuntos, y en general, cualquier agregado que sea iterable. Más adelante, en el tema de
tratamientos secuenciales avanzados, vemos el tipo Stream y los arrays de dos dimensiones.

2.1 Arrays
El recorrido de los elementos de un array o cualquier otro agregado indexado sigue el esquema:

E[] ag = ...;
...
for (int i = 0; i < ag.length; i++) {
T e = ag[i];
...
}
...

2.2 Secuencias Numéricas


Ejemplos de secuencias son: la secuencia aritmética de a hasta b con razón c (siendo b > a y c > 0); la
secuencia aritmética de a hasta b con razón c (siendo a > b y c < 0); y la secuencia geométrica de a hasta b
con razón c (siendo b > a y c > 1).
6 Introducción a la Programación

El esquema de generación de los números de la secuencia es:


for(i = a; i < b; i = i+c ) { // secuencia aritmética con a <= b, c > 0

}
for(i = a; i > b; i = i-c ) { // secuencia aritmética con a >= b, c > 0

}
for(i = a; i < b; i = i*c ) { // secuencia geométrica con a <= b, c > 1

}

2.3 El tipo Iterable


Cuando un agregado de datos implementa la interfaz Iterable, el recorrido en Java puede hacerse de la
forma:

Iterable<E> ag = ...;
...
for (E e : ag) {
...
}

Algunos tipos que implementan Iterable<E> son List<E>, Set<E> y SortedSet<E>.

3. Acumuladores

En este apartado se detallará un conjunto básico de acumuladores que son de uso muy general. Más
adelante se verá otro grupo de acumuladores más avanzados. Para describir los acumuladores se usará una
plantilla en la que se indicará el objetivo, el tipo de la variable del acumulador y los detalles de las funciones
que tiene asociadas.

Los acumuladores básicos los podemos agrupar, teniendo en cuenta si hay que recorrer el agregado
completamente o no, si acumulan realmente un valor o no, y si tienen relación con criterios de ordenación.
En los siguientes apartados se estudiarán los distintos tipos de acumuladores agrupados en relación a estas
características.

3.1 Acumuladores con una función salir que devuelve siempre falso
Este grupo de acumuladores tienen una función salir que devuelve siempre falso. Esto indica que para
devolver su resultado es necesario recorrer todos los elementos del agregado sobre el que se están
acumulando los valores. Note también que al devolver siempre falso la función salir, la línea de código
if(salir(a)) break; que aparece en el esquema general puede omitirse.

3.1.1 Suma (sum)

 Objetivo: Suma de los valores del agregado cuyos elementos deben ser de tipo numérico.
5. Tratamientos secuenciales básicos
7

 Tipo del acumulador: Double, Integer u otro tipo numérico.


 Valor Inicial: Cero.
 Expresión acumuladora: a = a +e.
 Salir(a): Falso
 Resultado(a): a

Un ejemplo de un acumulador suma de tipo Double en un tratamiento secuencial genérico con una fuente
de datos de tipo Iterable<T> es el siguiente:

Iterable<T> agregado = ...;


Double a = 0.0;
for (T e : agregado) {
if (Filtro(e)) {
Double b = Expresion(e);
a = a + b;
}
}
return a;

En el código anterior hemos asumido que el acumulador es de tipo Double y que el agregado de datos es de
tipo Iterable<T>. El esquema sería similar si el tipo del valor a acumular fuese cualquier otro tipo numérico.
Por ejemplo, si el valor a acumular es Integer, éste será el tipo de la variable res, que se inicializará a 1, y
Expresion devolverá un valor de tipo Integer.

3.1.2 Producto (multiply)

 Objetivo: Multiplicar los valores del agregado cuyos elementos deben ser de tipo numérico.
 Tipo del acumulador: Double, Integer u otro tipo numérico.
 Valor Inicial: Uno.
 Expresión acumuladora: a = a*e.
 Salir(a): Falso
 Resultado(a): a

Un ejemplo de un acumulador producto de tipo Double en un tratamiento secuencial genérico con una
fuente de datos de tipo Iterable<T> es el siguiente:

Iterable<T> agregado = ...;


Double a = 1.0;
for (T e : agregado) {
if (Filtro(e)) {
Double b = Expresion(e);
a = a * b;
}
}
return a;
8 Introducción a la Programación

3.1.3 Contador (count)

 Objetivo: Contar los elementos del agregado.


 Tipo del acumulador: Integer.
 Valor Inicial: Cero.
 Expresión acumuladora: a = a+1.
 Salir(a): Falso
 Resultado(a): a

Un ejemplo de un acumulador contador en un tratamiento secuencial genérico con una fuente de datos de
tipo Iterable<T> es el siguiente:

Iterable<T> agregado = ...;


Integer a = 0;
for (T e : agregado) {
if (Filtro(e)) {
a = a + 1;
}
}
return a;

3.1.4 Acumula Lista (toList)

 Objetivo: Devuelve en una Lista los elementos del agregado.


 Tipo del acumulador: List<E>
 Valor Inicial: Lista Vacía.
 Expresión acumuladora: a.add(e)
 Salir(a): Falso
 Resultado(a): a

Un ejemplo de un acumulador lista en un tratamiento secuencial genérico con una fuente de datos de tipo
Iterable<T> es el siguiente:

Iterable<T> agregado = ...;


List<E> a = new ArrayList<E>();
for (T e : agregado) {
if (Filtro(e)) {
E b = Expresión(e);
a.add(b);
}
}
return a;

3.1.5 Acumula Conjunto (toSet)

 Objetivo: Devuelve en un Conjunto los elementos del agregado.


 Tipo del acumulador: Set<E>
5. Tratamientos secuenciales básicos
9

 Valor Inicial: Conjunto Vacío.


 Expresión acumuladora: a.add(e)
 Salir(a): Falso
 Resultado(a): a

Un ejemplo de un acumulador lista en un tratamiento secuencial genérico con una fuente de datos de tipo
Iterable<T> es el siguiente:

Iterable<T> agregado = ...;


Set<E> a = new HashSet<E>();
for (T e : agregado) {
if (Filtro(e)) {
E b = Expresion(e);
a.add(b);
}
}
return a;

De forma similar tendríamos el acumula conjunto ordenado u otros similares

3.1.6 Acumula Array (toArray)

 Objetivo: Devuelve un array de elementos tipo E con los elementos del agregado colocados en las
casillas del array y el número de elementos de este array.
 Tipo del acumulador: (E[] a, i)
 Valor Inicial: (new E[m], 0). Con m suficiente para asegurar m mayor que el tamaño del agregado.
 Expresión acumuladora: (a[i] = e, i++)
 Salir(a): Falso
 Resultado(a,i): (a,i)

Un ejemplo de un acumulador array en un tratamiento secuencial genérico con una fuente de datos de tipo
Iterable<T> es el siguiente:

Iterable<T> agregado = …;
int num = … //número de elementos del agregado
int i = 0;
E []a = new E[num];
for (T e : agregado) {
if (Filtro(e)) {
E b = Expresion(e);
a[i] = b;
i++;
}

}
return a;
10 Introducción a la Programación

El esquema es más complejo que en el caso de seleccionar listas o conjuntos. La razón es que los arrays son
agregados de datos de tamaño constante. Por lo tanto, debemos conocer su tamaño para poder crearlos.
Para poder hacerlo debemos o bien contar los elementos que pasan el filtro, o bien contar los elementos del
agregado. Luego debemos crear un array de ese tamaño y, por último, colocar los sucesivos valores
calculados en las casillas que tienen un índice i dado. El índice se irá actualizando a medida que vayamos
encontrando objetos que pasan el filtro.

3.2 Acumulador que no acumula


El acumulador de este bloque en realidad no pretende acumular nada, sino solamente modificar los
elementos del agregado aplicándoles la operación op(e). Podemos decir que este acumulador es un
acumulador singular porque no acumula nada. Pero sí comparte el mismo esquema que los demás
acumuladores.

3.2.1 Ejecuta Para Todo

 Objetivo: Ejecuta una acción sobre cada elemento del agregado. Una acción es una sentencia
construida sobre la variable e que puede producir efectos laterales sobre la misma, es decir, cambiar
su estado. Los elementos deben ser de un tipo mutable.
 Tipo del acumulador: No hay
 Valor Inicial: No hay
 Expresión acumuladora: op(e)
 Salir(a): Falso
 Resultado(a): no hay

Un ejemplo de un ejecuta para todo en un tratamiento secuencial genérico con una fuente de datos de tipo
Iterable<T> es el siguiente:

Iterable<T> agregado = ...;


for (T e : agregado) {
if (Filtro (e)) {
Accion(e);
}
}

3.3 Acumuladores con función salir


Veamos ahora el segundo bloque: operaciones que pueden calcular su valor en muchos casos sin recorrer
completamente el agregado. Los esquemas tienen una estructura similar, pero la iteración puede terminar
con la sentencia break, cuando ya se conoce el resultado.

3.3.1 Para Todo (all)

 Objetivo: Decide si todos los elementos del agregado cumplen una propiedad p(e). p(e) es una
función booleana que se aplica sobre e.
 Tipo del acumulador: Boolean
5. Tratamientos secuenciales básicos
11

 Valor Inicial: true


 Expresión acumuladora: a = p(e)
 Salir(a): !a
 Resultado(a): a

Un ejemplo de un acumulador para todo en un tratamiento secuencial genérico con una fuente de datos de
tipo Iterable<T> es el siguiente:

Iterable<T> agregado = ...;


Boolean a = true;
for (T e : agregado) {
if (Filtro(e)) {
Boolean a = p(e);
if(!a) {break};
}
}
return a;

3.3.2 Existe (any)

 Objetivo: Decide si alguno de los elementos del agregado cumple la propiedad p(e).
 Tipo del acumulador: Boolean
 Valor Inicial: false
 Expresión acumuladora: a = p(e)
 Salir(a): a
 Resultado(a): a

Un ejemplo de un acumulador existe en un tratamiento secuencial genérico con una fuente de datos de tipo
Iterable<T> es el siguiente:

Iterable<T> agregado = ...;


Boolean a = false;
for (T e : agregado) {
if (Filtro (e)) {
Boolean a = p(e);
if(a) {break};
}
}
return a;

3.3.3 Busca Primero (first)

 Objetivo: Buscar, si existe, el primer objeto que cumple una propiedad p(e). Si no existe eleva la
excepción NoSuchElementException.
 Tipo del acumulador: E
 Valor Inicial: null
12 Introducción a la Programación

 Expresión acumuladora: if (p(e)) a = e;


 Salir(a): a !=null
 Resultado(a): a

Un ejemplo de un acumulador busca primero en un tratamiento secuencial genérico con una fuente de
datos de tipo Iterable<T> es el siguiente:

Iterable<T> agregado = ...;


T a = null;
for (T e : agregado) {
if (Filtro (e)) {
Boolean b = p(e);
if(b) {
a = e;
break;
}
}
}
if(a == null)
throw new NoSuchElementException();
return a;

Note que en este caso, la función salir será cierta en el momento en el que se cumpla la propiedad p(e). Esto
hace que la comprobación explícita de la función de salida se haya omitido. Se ha optado por combinar la
operación de acumulación y la de salida en el mismo bucle if.

3.3.4 Posición del Primero (index)

 Objetivo: buscar, si existe, la posición del primer objeto que cumple una propiedad p(e). Si no existe
devuelve -1.
 Tipo del acumulador: (a,i): (Integer, Integer)
 Valor Inicial: (-1,0)
 Expresión acumuladora: if (p(e)) {a=i;} i++;
 Salir(a): a != -1
 Resultado(a): a

Un ejemplo de un acumulador posición del primero en un tratamiento secuencial genérico con una
fuente de datos de tipo Iterable<T> es el siguiente:

Iterable<T> agregado = ...;


int res = -1;
int i=0;
for (T e : agregado) {
if (Filtro (e)) {
Boolean b = p(e);
if(b) {
res = i;
break;
}
5. Tratamientos secuenciales básicos
13

}
i++;
}
return res;

Note que en este caso, la función salir será cierta en el momento en el que se cumpla la propiedad p(e). Esto
hace que, igual que ocurría en el caso anterior, la comprobación explícita de la función de salida se haya
omitido. Se ha optado por combinar la operación de acumulación y la de salida en el mismo bucle if.

3.4 Esquemas que dependen de órdenes


Veamos ahora algunos valores acumulados que dependen de órdenes.

3.4.1 Máximo (max)

 Objetivo: Calcula el máximo de los elementos del agregado. El máximo se calcula con respecto a un
orden dado. En este tema nos ceñiremos al orden natural de los tipos, pero, posteriormente, cuando
veamos los tratamientos secuenciales avanzados, el orden se representará por un Comparator<E>. Si
el agregado es vacío devuelve la excepción NoSuchElementException.
 Tipo del acumulador: E
 Valor Inicial: null
 Expresión acumuladora1:

if(a == null || e.compareTo(a) > 0) a = e;

 Salir(a): false
 Resultado(a): a

Un ejemplo de un acumulador máximo en un tratamiento secuencial genérico con una fuente de datos de
tipo Iterable<T> y en el que interviene el orden natural es el siguiente:

Iterable<T> agregado = ...;


T2 a = null;
for (T e : agregado) {
if (e != null && Filtro (e)) {
T2 exp = Expresion (e);
if (a== null || exp.compareTo(a) >0){
a= exp;
}
}
}
if (a == null)
throw new NoSuchElementException();
return a;

1
Esta expresión se generalizará en el tema de tratamientos secuenciales avanzados para trabajar con Comparator<T>
14 Introducción a la Programación

3.4.2 Mínimo (min)

 Objetivo: Calcula el mínimo de los elementos del agregado. El máximo se calcula con respecto a un
orden dado representado por el Comparator<E> ord. Si el agregado es vacío devuelve la excepción
NoSuchElementException.
 Tipo del acumulador: E
 Valor Inicial: null
 Expresión acumuladora2:

if(a == null || e.compareTo(a) < 0) a = e;

 Salir(a): false
 Resultado(a): a

Un ejemplo de un acumulador mínimo en un tratamiento secuencial genérico con una fuente de datos de
tipo Iterable<T> y en el que interviene el orden natural es el siguiente:

Iterable<T> agregado = ...;


T2 a = null;
for (T e : agregado) {
if (e != null && Filtro (e)) {
T2 exp = Expresion (e);
if (a== null || exp.compareTo(a) < 0){
a= exp;
}
}
}
if (a == null)
throw new NoSuchElementException();
return a;

4. Ejemplos y metodología de trabajo

Los esquemas anteriores se repiten muy frecuentemente. Para poder usarlos debemos identificar en primer
lugar cada uno de sus elementos:

 ¿Cuál es la fuente de datos?


 ¿Cuál es el mecanismo para generar los datos?
 ¿Cuál es el filtro, si lo hay?
 ¿Cuál es la transformación a usar?
 ¿Cuál de los acumuladores usar?

2
Esta expresión se generalizará en el tema de tratamientos secuenciales avanzados para trabajar con Comparator<T>
5. Tratamientos secuenciales básicos
15

Para los ejemplos siguientes suponemos implementados los tipos propuestos como ejercicios en el tema
anterior.

Ejemplo 5. Ejemplo de esquema secuencial con acumulador suma.

Si queremos diseñar un método static de la clase Personas, tomando como parámetro una lista de Persona y
una edad que debe ser positiva, devuelva como resultado la suma de las edades de las personas contenidas
en la lista que sean mayores que la edad dada. No hay garantías de que los objetos en la lista sean distintos
de null. En este caso tenemos:

 Origen de datos: la lista


 Generación de datos: la lista es iterable
 Filtro: la persona debe ser distinta de null
 Transformación: calcula la edad de una persona
 Esquema a usar: suma

El código resultante, donde puede verse el código concreto del filtro y de la expresión, es:

public static Integer sumaEdades(List<Persona> lista, Integer ed) {


Integer suma = 0;
for (Persona p : lista) {
if(p != null && p.getEdadd()>ed) {
Integer e = p. e.getEdad();
suma = suma + e;
}
}
return suma;
}

Ejemplo 6. Esquema de tratamiento secuencial acumula lista.

Dado un array de String cada una de las cuales representa un Double, obtener una lista de Double.

public static List<Double> getLista (String[] ag) {


List<Double> l = new ArrayList<Double>();
for (String s : ag) {
Double e = new Double(s);
l.add(e);
}
return l;
}

Ahora hemos usado el esquema acumula lista, no hay filtro y new Double (e) es la transformación que
construye objetos de tipo Double.

Ejemplo 7. Esquema de tratamiento secuencial acumula conjunto.

Implementar el método getLibros en la clase Bibliotecas que dada una Biblioteca y dos fechas, la segunda
mayor que la primera, devuelva todos los libros distintos que fueron adquiridos entre esas dos fechas.
16 Introducción a la Programación

public static Set<Libro> getLibros (Biblioteca b, LocalDate f1, LocalDate f2) {


if(!(f1.isBefore(f2))) {
throw new IllegalArgumentException();
}
Set<Libro> res = new HashSet<Libro>();
for(Libro lib: b.getLibros()) {
LocalDate f = lib.getFechaAdquisicion();
if(f.ifAfter(f1) && f.isBefore(f2){
res.add(f);
}
}

return res;
}

Ahora hemos usado el esquema acumula conjunto, y el filtro es que la fecha esté comprendida
estrictamente entre las dos proporcionadas. Suponemos que todos los libros son distintos de null. El origen
de datos tiene una lista de libros. Las listas son iterables.

Ejemplo 8. Esquema de tratamiento secuencial contador.

Dado un array de Punto, obtener cuántos hay con sus coordenadas x e y positivas.

public static Integer getNumeroEnPrimerCuadrante (Punto[] ap) {


Integer num = 0;
for (int i = 0; i < ag.length ; i++) {
Punto e = ap[i];
if(e!=null && e.getX().compareTo(0.0)> 0 && e.getY().compareTo(0.0)>0) {
num++;
}
}
return num;
}

Ahora hemos usado el esquema contar, el filtro es que el punto sea distinto de null y tenga las coordenadas
x e y positivas.

Ejemplo 9. Esquema de tratamiento secuencial acumula conjunto.

Dada una lista de Viaje calcular cuántas ciudades distintas pueden visitarse si se hacen todos los viajes de la
lista que sean posibles para un grupo formado por un número dado de personas.

public static Integer getCiudadesDistintas (List<Viaje> lista, Integer n) {


if(n <= 0){
throw new IllegalArgumentException();
}
Set<String> sr = new HashSet<String>();
for (Viaje e : lista) {
if(e.getMinimoDePersonas() >= n) {
sr.addAll(e.getCiudadesVisitadas());
}
}

return sr.size();
5. Tratamientos secuenciales básicos
17

Ahora hemos usado el esquema acumula conjunto, el filtro es que el grupo sea mayor o igual al entero dado.
El número de objetos distintos es el cardinal del conjunto construido. Podemos observar que el origen de
datos está compuesto de una lista cada uno de cuyos objetos tiene una propiedad que es otra lista.

Ejemplo

Dada una lista de Circulo diseñar un método static que nos devuelva el que tenga un área mayor de entre los
que tengan un radio mayor a un número dado.

public static Circulo getMayorArea (List<Circulo> lista, Double umbral) {


Circulo elMax = null;
for (Circulo c : lista) {
if (c!=null && c.getRadio().compareTo(umbral)>0) {
if(elMax == null || c.getArea().compareTo(elMax.getArea()) > 0) {
elMax = e;
}
}
}
if(elMax == null)
throw new NoSuchElementException();
return elMax;
}

5. Ejercicios

1. Dada una lista de números enteros, que se toma como parámetro, implemente un método de utilidad en
la clase Enteros para responder a cada una de las siguientes cuestiones:
a) ¿Todos los elementos de la lista son impares?
b) ¿Existe alguno que sea impar y primo? Supóngase implementado previamente el método
esPrimo.
c) ¿Cuántos enteros impares y primos hay?
d) ¿Cuál es el valor de la suma de los enteros que son primos? ¿Y del producto de los que son
impares?
e) ¿Hay alguno que divida a un número n (siendo n un parámetro del método)?
f) Busque todos los enteros pares que estén en la lista de entrada (que el método devuelva el
resultado en otra lista)

2. Dado un Set<List<Integer>> que se toma como parámetro, implemente un método en la clase de utilidad
Enteros para responder a cada una de las siguientes cuestiones:
a) ¿Cuánto vale la suma de todos los elementos que son impares?
b) ¿Cuál es el entero más pequeño? ¿y el más grande?
c) ¿Existe algún elemento que sea primo?
d) ¿Existe algún elemento que sea primo y que ocupe la primera posición de cada lista del
conjunto?
e) Devuelva un List<Integer> con todos aquellos enteros que ocupan la primera posición en cada
lista del conjunto.
18 Introducción a la Programación

3. Dado un Set<List<Integer>> que se toma como parámetro, implemente un método en la clase de utilidad
Enteros para resolver cada una de las siguientes cuestiones:
a) ¿Cuál es la lista de mayor tamaño?
b) ¿Existe alguna lista que contenga algún entero con valor negativo?
c) ¿Todas las listas son de tamaño mayor que 2?
d) ¿Cuánto suman todos los números enteros del conjunto de listas?

4. Dada una colección de libros, implemente un método estático para resolver cada uno de los siguientes
apartados:
a) Encontrar el título del libro más barato escrito por “George R. R. Martin”.
b) Calcular el total de páginas de todos los libros del autor anterior.
c) Calcular la media de páginas de los libros del autor anterior.
d) Cambiar el tipo de préstamo a MENSUAL de todos los libros que tengan al menos 1000 páginas.

5. Dada una colección de bibliotecas, implementa un método estático para:


a) Seleccionar en una lista aquellas bibliotecas que tengan disponible algún libro de “George R. R.
Martin”.
b) Cambiar el tipo de préstamo a MENSUAL de todos los libros que tengan al menos 1000 páginas.

6. Dadas las siguientes interfaces:


public interface Destino extends Comparable<Destino> {
Double getDistancia();
String getNombre();
}
public interface Vuelo {
Destino getDestino();
Double getPrecio();
Integer getNumPlazas();
Integer getNumPasajeros();
Integer getCodigo();
Fecha getFechaSalida();
Persona getPiloto();
}
public interface CompañiaAerea {
Integer getCodigo();
String getNombre();
Vuelo[] getVuelos();
}

Implemente los siguientes métodos en la clase Compañias:

a) Un método que dada una compañía aérea devuelva el nombre del piloto del primer vuelo (de
salida más pronto) con plazas libres con destino París.
b) Un método que dada una compañía aérea devuelva el código del vuelo que más distancia recorre
de entre los que salen hoy.

También podría gustarte