N3: MANEJO DE GRUPOS DE ATRIBUTOS

Nychol Bazurto Gómez

Contenedoras de tamaño fijo

Nivel

3

Instrucciones repetitivas

Contenedoras de tamaño variable

Uso de ciclos

Creación de una clase

Qué vamos a aprender

  • Estructuras contenedoras, que nos permiten manejar atributos cuyo valor corresponde a una secuencia de elementos.
  • Instrucciones repetitivas, que son instrucciones que nos permiten manipular los elementos contenidos en dichas secuencias.
  • Recorridos
    • Totales
    • Parciales
    • Dobles
  • Crear una clase completa en java utilizando eclipse.

Caso de estudio No. 1: EL REFUGIO de perros

  • En el refugio hay 10 perros
  •  De cada perro se tiene la edad (un valor entre 0.0 y 14.0)

Se quiere construir un programa que permita:

1. Cambiar la edad de un perro.

2. Calcular el promedio de edad del refugio

3. Establecer el número de perros que están por encima de dicho promedio.

EL REFUGIO DE PERROS

R1: Cambiar edad

Resumen: Permite cambiar la edad de un perro del refugio.

Entradas

1. El perro a quien se quiere cambiar la edad

2. La nueva edad del perro

Se ha asignado al perro la nueva edad.

Resultado

EL REFUGIO DE PERROS

R2: Calcular el promedio

Resumen: Permite calcular la edad promedio de los perros del refugio.

Entradas

Ninguna

El promedio de las edades de los diez perros del refugio.

Resultado

EL REFUGIO DE PERROS

R3: Calcular el número de perros por encima del promedio.

Resumen: Permite saber cuántos perros tienen una edad superior a la edad promedio del refugio.

Entradas

Ninguna

Número de perros con edad mayor al promedio del erfugio

Resultado

MODELO

Refugio
double edad1;
double edad2;
double edad3;
double edad4;
double edad5;
double edad6;
double edad7;
double edad8;
double edad9;
double edad10;

USANDO CONTENEDORES

Refugio
double edad1;
double edad2;
double edad3;
double edad4;
double edad5;
double edad6;
double edad7;
double edad8;
double edad9;
double edad10;
Refugio
double[] edades =












 
0
1
2
3
4
5
6
7
8
9

Un solo atributo llamado edades

ARREGLO = CONTENEDORA DE TAMAño fijo

5 6.7 2 3.5 10 7 8 1.2 1 0

edades =

edades[0]

edades[4]

edades[8]

0

1

2

3

4

5

6

7

8

9

Cada posición del arreglo (casilla) se utiliza como una variable

edades[5] = 3.0;
i = 2;
if ( edades[ i ] > 4.0)
edades[7] = edades[3];
if (edades[6] == edades[0])
edades[0] = 2.0;
else
edades[0] = edades[9];

Contenedoras de tamaño fijo

  • Definir que van a “contener”: int, double, String, char, boolean u objetos.
  • Una vez definido el tipo se pueden declarar como atributos:
    • private <tipo>[]  <nombre>;
    • Ejemplo: private double[] notas;
    • Ejemplo: private Perro[] perros;
  • Se pueden declarar como variables temporales (dentro de métodos), aunque no es algo usual:
    • <tipo>[] nombre;
    • Ejemplo: double[] notas;
    • Ejemplo: Perro[] perros;

Contenedoras de tamaño fijo

  • Para el caso de los perros, suponemos que la clase Perro tiene el siguiente constructor:
    • public Perro (String pNombre, double pEstatura)
  • La inicialización de los elementos del arreglo perros sería:
  • perros [0] = new Perro(“Kaiser”, 1.23);

    perros [1] = new Perro(“Balto”, 0.85);

    perros[CANT_PERROS-1] = new Perro(…);

    ó

    perros[perros.length-1] = new Perro(…);

 perros = new Perro[ TOTAL_PERROS ] ;

Contenedoras de tamaño fijo

  • Si se trata de acceder a una casilla con índice menor que 0 o mayor que el número máximo de casillas (en este caso 10) java.lang.ArrayIndexOutOfBoundsException

INSTRUCCIONES REPETITIVAS

Una solución puede lograrse repitiendo un paso que vaya transformando gradualmente el estado del mundo modelado

CALCULAR EL PROMEDIO DE EDADES

1. Sumar todas las edades.

2. Dividir por el número de perros.

public double promedio( )
{
    double suma = perros[ 0 ] + perros[ 1 ] + perros[ 2 ] + 
                  perros[ 3 ] + perros[ 4 ] + perros[ 5 ] + 
                  perros[ 6 ] + perros[ 7 ] + perros[ 8 ] + 
                  perros[ 9 ] + perros[ 10 ] + perros[ 11 ];
    return suma / TOTAL_PERROS;
}

CALCULAR EL PROMEDIO DE EDADES

public double promedio( )
{ 
    double suma = 0.0;
    int indice = 0;

    suma += perros[ indice ]; 
    indice++;
    suma += perros[ indice ]; 
    indice++;
    suma += perros[ indice ]; 
    indice++;
    suma += perros[ indice ]; 
    indice++;
    suma += perros[ indice ]; 
    indice++;
    suma += perros[ indice ]; 
    indice++;
    suma += perros[ indice ]; 
    indice++;
    suma += perros[ indice ]; 
    indice++;
    suma += perros[ indice]; 
    indice++;
    suma += perros[ indice ]; 
    indice++;
    suma += perros[ indice ]; 
    indice++;
    suma += perros[ indice ];

    return suma / TOTAL_PERROS;
}

Utiliza un índice que va desplazando desde 0 hasta 11

Paso que se repite

CALCULAR EL PROMEDIO DE EDADES

public double darPromedio( )
{
    double suma = 0.0;
    int indice = 0;
    while( indice < TOTAL_PERROS )
    {
        suma += perros[ indice ]; 
        indice++;
    }
    return suma / TOTAL_PERROS;
}

se encarga de ejecutar repetidamente las instrucciones que tiene en su interior

"mientras que" una condición se cumpla, siga ejecutando las instrucciones que están por dentro.

"mientras que" el índice no llegue a 12, vuelva a ejecutar la pareja de instrucciones que tiene asociadas.

Componentes de una Instrucción Repetitiva

inicio

Preparación del ciclo

¿La condición es verdadera?

SI

NO

termina el ciclo

Ejecuta las instrucciones del cuerpo del ciclo

Componentes de una Instrucción Repetitiva

inicio

Preparación del ciclo

¿La condición es verdadera?

SI

NO

termina el ciclo

Ejecuta las instrucciones del cuerpo del ciclo

public double darPromedio( )
{
    double suma = 0.0;
    int indice = 0;
    while( indice < TOTAL_PERROS )
    {
        suma += perros[ indice ]; 
        indice++;
    }
    return suma / TOTAL_PERROS;
}

Las Instrucciones WHILE y FOR

<inicio>
while( <condición> )
{
    <cuerpo>
    <avance>
}
for (<inicio>; <condición>; <avance>)
{
<cuerpo>
}

Las Instrucciones WHILE y FOR

public double darPromedio( )
{
    double suma = 0.0;
    int indice = 0;
    while( indice < TOTAL_PERROS )
    {
        suma += perros[ indice ]; 
        indice++;
    }
    return suma / TOTAL_PERROS;
}

Inicio de las variables de trabajo: 

• Indice para movernos en el arreglo. 

• Acumulado de la suma de las edades. 

Las Instrucciones WHILE y FOR

public double darPromedio( )
{
    double suma = 0.0;
    int indice = 0;
    while( indice < TOTAL_PERROS )
    {
        suma += perros[ indice ]; 
        indice++;
    }
    return suma / TOTAL_PERROS;
}

 

Condición para continuar:

• Cualquier expresión lógica

 

Las Instrucciones WHILE y FOR

public double darPromedio( )
{
    double suma = 0.0;
    int indice = 0;
    while( indice < TOTAL_PERROS )
    {
        suma += perros[ indice ]; 
        indice++;
    }
    return suma / TOTAL_PERROS;
}

 

Cuerpo del ciclo:

• Instrucciones que se van a repetir en cada iteración

 

Las Instrucciones WHILE y FOR

public double darPromedio( )
{
    double suma = 0.0;
    int indice = 0;
    while( indice < TOTAL_PERROS )
    {
        suma += perros[ indice ]; 
        indice++;
    }
    return suma / TOTAL_PERROS;
}

 

 

Avance del ciclo:

• Incremento del índice que indica la posición del arreglo en la que estamos en un momento dado

 

Las Instrucciones WHILE y FOR

public double darPromedio( )
{
    double suma = 0.0;
    for ( int indice = 0; indice < TOTAL_PERROS; indice ++ ) 
    { 
       suma += perros[ indice ]; 
    } 
    suma = suma / TOTAL_PERROS; 
    return suma;
}

Inicio de las variables de trabajo: 

• Indice para movernos en el arreglo. 

• Acumulado de la suma de las edades. 

Las Instrucciones WHILE y FOR

public double darPromedio( )
{
    double suma = 0.0;
    for ( int indice = 0; indice < TOTAL_PERROS; indice ++ ) 
    { 
       suma += perros[ indice ]; 
    } 
    suma = suma / TOTAL_PERROS; 
    return suma;
}

 

Condición para continuar:

• Cualquier expresión lógica

 

Las Instrucciones WHILE y FOR

public double darPromedio( )
{
    double suma = 0.0;
    for ( int indice = 0; indice < TOTAL_PERROS; indice ++ ) 
    { 
       suma += perros[ indice ]; 
    } 
    suma = suma / TOTAL_PERROS; 
    return suma;
}

 

Cuerpo del ciclo:

• Instrucciones que se van a repetir en cada iteración

 

Las Instrucciones WHILE y FOR

public double darPromedio( )
{
    double suma = 0.0;
    for ( int indice = 0; indice < TOTAL_PERROS; indice ++ ) 
    { 
       suma += perros[ indice ]; 
    } 
    suma = suma / TOTAL_PERROS; 
    return suma;
}

 

 

Avance del ciclo:

• Incremento del índice que indica la posición del arreglo en la que estamos en un momento dado

 

PRACTIQUEMOS

 Calcular el número de perros que tienen una edad entre 2 y 8.

public int cuantosTienenEdadEnRango ( ) 
{
    ...
}

Calcular la mayor edad del refugio.

public int mayorEdad ( ) 
{
    ...
}

Contar el número de perros que tienen una edad inferior a la del perro que está en la posición del arreglo que llega como parámetro. Suponga que el parámetro posPerro tiene un valor entre 0 y TOTAL_PERROS-1

public int cuantosMenoresQue ( int posEst ) 
{
    ...
}

Incrementar todas las edades de los perros en 1.

public void incrementarEdad ( ) {
    ...
}

PATRONES DE ALGORITMO PARA INSTRUCCIONES REPETITIVAS

Un patrón de algoritmo se puede ver como una solución genérica para un tipo de problemas, en la cual el programador sólo debe resolver los detalles particulares de su problema específico.

  • Patrón de Recorrido Total

  • Patrón de Recorrido Parcial

  • Patrón de Doble Recorrido

PATRÓN DE RECORRIDO TOTAL

¿Cuándo usarlo?

Se necesita recorrer TODO el arreglo y además ACUMULAR o CALCULAR alguna propiedad sobre TODOS los elementos.

  • Calcular la suma de todas las edades.
  • Contar cuántos perritos tienen más de 9 años.
  • Contar cuántos están por debajo del promedio de edad.

Ejemplos

  1. El índice para iniciar el ciclo debe empezar en cero.
  2. La condición para continuar es que el índice sea menor que la longitud del arreglo.
  3. El avance consiste en sumarle uno al índice.

PATRÓN DE RECORRIDO TOTAL

for( int indice = 0; indice < arreglo.length; indice++ )
{
    <cuerpo>
}

 

Indice para movernos en el arreglo empieza en CERO

 

Condición para continuar: índice menor que la longitud del arreglo

Avance: incremento en 1 del índice

PATRÓN DE RECORRIDO TOTAL

¿Cuándo usarlo?

Se necesita recorrer TODO el arreglo y además ACUMULAR o CALCULAR alguna propiedad sobre TODOS los elementos.

Decisiones a tomar:

– ¿Cómo acumular?

– ¿Cómo inicializar el acumulado?

– ¿Condición para cambiar el acumulado?

– ¿Cómo cambiar el acumulado?

PATRÓN DE RECORRIDO TOTAL

¿Cuándo usarlo?

Se necesita recorrer TODO el arreglo y además ACUMULAR o CALCULAR alguna propiedad sobre TODOS los elementos.

public int darCantidadPerrosAdultos( )
{ 
    int vanAdultos = 0;
    for( int i = 0; i < perros.length; i++ )
    {
        if( perros[ i ] >= 2.0 )
        {
            vanAdultos++;
        }    
    } 
    return vanAdultos;
}

¿Cómo acumular?

Con una variable

PATRÓN DE RECORRIDO TOTAL

¿Cuándo usarlo?

Se necesita recorrer TODO el arreglo y además ACUMULAR o CALCULAR alguna propiedad sobre TODOS los elementos.

public int darCantidadPerrosAdultos( )
{ 
    int vanAdultos = 0;
    for( int i = 0; i < perros.length; i++ )
    {
        if( perros[ i ] >= 2.0 )
        {
            vanAdultos++;
        }    
    } 
    return vanAdultos;
}

¿Cómo inicializar el acumulado?

En cero o en un valor adaptado al problema

PATRÓN DE RECORRIDO TOTAL

¿Cuándo usarlo?

Se necesita recorrer TODO el arreglo y además ACUMULAR o CALCULAR alguna propiedad sobre TODOS los elementos.

public int darCantidadPerrosAdultos( )
{ 
    int vanAdultos = 0;
    for( int i = 0; i < perros.length; i++ )
    {
        if( perros[ i ] >= 2.0 )
        {
            vanAdultos++;
        }    
    } 
    return vanAdultos;
}

¿Condición para cambiar el acumulado?

En este ejemplo, cuando el elemento que se está revisando sea mayor o

igual a 2

PATRÓN DE RECORRIDO TOTAL

¿Cuándo usarlo?

Se necesita recorrer TODO el arreglo y además ACUMULAR o CALCULAR alguna propiedad sobre TODOS los elementos.

public int darCantidadPerrosAdultos( )
{ 
    int vanAdultos = 0;
    for( int i = 0; i < perros.length; i++ )
    {
        if( perros[ i ] >= 2.0 )
        {
            vanAdultos++;
        }    
    } 
    return vanAdultos;
}

¿Cómo modificar el acumulado?

 

En este ejemplo, incrementándolo en 1

PATRÓN DE RECORRIDO PARCIAL

¿Cuándo usarlo?

Se usa cuando NO se necesita recorrer TODO el arreglo

Existe una condición que debemos verificar en cada iteración para saber si debemos detener el ciclo o volver a repetirlo.

Ejemplos

–Decidir si al menos un perro tiene 5 años.

–Buscar el primer perro con edad igual a 1.

- Indicar si más de 3 perros son adultos.

PATRÓN DE RECORRIDO PARCIAL

boolean termino = false;

for( int i = 0; i < arreglo.length && !termino; i++ )
{
    <cuerpo>

    if( <ya se cumplió el objetivo> ) 
    {
        termino = true;
    }   
}

Utilizar una variable auxiliar (centinela) facilita el manejo de la condición a calcular.

PATRÓN DE RECORRIDO PARCIAL

public boolean algunoConCinco ( ) 
{ 
    boolean termino = false;
    for ( int i = 0; i < perros.length && !termino; i++) 
    { 
        if ( perros[ i ] == 5.0 ) 
            termino = true; 
    } 
    return termino; 
}

PATRÓN DE RECORRIDO PARCIAL

public boolean alguienConCinco ( )
{
    int i = 0;
    while ( i < perros.length && perros[ i ] != 5.0 )
    {
        i++;
    }
    if ( i == perros.length)
        return false;
    else
        return true;
}

PATRÓN DE RECORRIDO PARCIAL CON ACUMULADO

  • Se usa cuando NO se necesita recorrer TODO el arreglo, sino hasta que se cumpla una condición y además

•Se necesita ACUMULAR o CALCULAR alguna propiedad sobre los elementos

PATRÓN DE RECORRIDO PARCIAL CON ACUMULADO

public void subirTresEdades( )
{
    int numEdades = 0;
    boolean termino = false;
    for ( int i = 0; i < perros.length && !termino; i++)
    {
        if ( perros[ i ] == 1.5 )
        {
            numEdades++;
            perros[ i ] = 2.5;
        }
        if ( numEdades == 3 )
        termino = true;
    }

PATRÓN DE RECORRIDO PARCIAL CON ACUMULADO SIN CENTINELA

public void subirTresEdades( )
{
    int numEdades = 0;
    for ( int i = 0; i < perros.length && numEdades < 3; i++)
    {
        if ( perros[ i ] == 1.5 )
        {
            numEdades++;
            perros[ i ] = 2.5;
        }
    }
}

PATRÓN DE RECORRIDO DOBLE

Solución de aquellos problemas en los cuales, por cada elemento de la secuencia, se debe hacer un recorrido completo.

Encontrar la edad que aparece un mayor número de veces en el refugio.

for( int indice1 = 0; indice1 < arreglo.length; indice1++ )
{
    for( int indice2 = 0; indice2 < arreglo.length; indice2++ )
    {
        <cuerpo del ciclo interno>
    }

    <cuerpo del ciclo externo>
}

PATRÓN DE RECORRIDO DOBLE

for( int indice1 = 0; indice1 < arreglo.length; indice1++ )
{
    for( int indice2 = 0; indice2 < arreglo.length; indice2++ )
    {
        <cuerpo del ciclo interno>
    }

    <cuerpo del ciclo externo>
}
  • El ciclo de afuera está manejado por la variable indice1.
  • El ciclo interno por la variable indice2.

¿Podemos usar dentro del cuerpo del ciclo interno la variable indice1?

patrón de algoritmo de recorrido total con doble recorrido

public double darEdadMasRecurrente( )
{
    double edadMasRecurrente = 0.0;

    for( int i = 0; i < perros.length; i++ )
    {
        for( int j = 0; j < perros.length; j++ )
        {

            //Por completar

        }
    }

    return edadMasRecurrente ;
}

patrón de algoritmo de recorrido total con doble recorrido

 (1) Contar el número de veces que aparece en el arreglo el valor que está en la casilla i;

 

(2) encontrar el mayor valor entre los que son calculados por el primer problema.

patrón de algoritmo de recorrido total con doble recorrido

 (1) Contar el número de veces que aparece en el arreglo el valor que está en la casilla i;

public double darEdadMasRecurrente( )
{
    double edadMasRecurrente = 0.0;

    for( int i = 0; i < perros.length; i++ )
    {
        double edadBuscada = notas[ i ]; 
        int contador = 0;

        for( int j = 0; j < perros.length; j++ )
        {
            if( perros[ j ] == edadBuscada ) 
            {
                contador++;
            }    
        }

        //Por completar
    }
    return edadMasRecurrente ;
}

(2) encontrar el mayor valor entre los que son calculados por el primer problema.

public double darEdadMasRecurrente( )
{
    double edadMasRecurrente = 0.0;
    int cantidadOcurrencias= 0;

    for( int i = 0; i < perros.length; i++ )
    {
        double edadBuscada = perros[ i ]; 
        int contador = 0;

        for( int j = 0; j < perros.length; j++ )
        {
            if( perros[ j ] == edadBuscada ) 
            {
                contador++;
            }    
        }

        if( contador > cantidadOcurrencias)
        {
            edadMasRecurrente = edadBuscada;
            cantidadOcurrencias= contador;
        }
    }
    return edadMasRecurrente ;
}
  • Debemos identificar los dos problemas que queremos resolver (uno con cada ciclo) y, luego, debemos tratar de resolverlos independientemente, usando los patrones de recorrido total o parcial.
  • Si para resolver un problema se necesita un tercer ciclo anidado, debemos escribir métodos separados que ayuden a resolver cada problema individualmente, tal como se plantea en el nivel 4, porque la solución directa es muy compleja y propensa a errores.

Contenedoras de tamaño variable = VECTOR

Necesitamos representar grupos de atributos para los cuales no conocemos su tamaño máximo.

import java.util.*; 

public class Ejemplo
{

...
private ArrayList<Tipo> nombre;



}

Para implementarlas en Java es necesario utilizar una clase de Java que se llama ArrayList (se encuentra en el paquete java.util)

Contenedoras de tamaño variable = VECTOR

  • Al crear un vector se reserva un espacio variable para almacenar los elementos que vayan apareciendo. Inicialmente hay 0 objetos en él.
...

nombre = new ArrayList<Tipo>( );

 

  • isEmpty( ): es un método que retorna verdadero si el vector no tiene elementos y falso en caso contrario. 
  • size( ): es un método que retorna el número de elementos que hay en el vector. 

DIFERENCIAS ENTRE ARREGLOS Y VECTORES

  • Tamaño fijo
  • Permite almacenar elementos de tipo simple (int, float, double) y objetos.
  • Para implementarlos en java, existe una sintaxis especial:
    • [ ]: para obtener un elemento del arreglo
    • length: para conocer la longitud

ARREGLO

VECTOR

  • Tamaño variable
  • NO permite almacenar elementos de tipo simple (int, float, double), SOLO objetos
  • Para implementarlos en java debemos utilizar una clase especial de java (ArrayList).
  • Para manipular un vector se utiliza entonces la misma sintaxis que utilizamos para manejar cualquier otra clase (llamado a métodos)

DIFERENCIAS ENTRE ARREGLOS Y VECTORES

Fijo Variable
Nombre Arreglos Vectores
En Java tipo[] ArrayList<tipo>
Conocer el tamaño .length .size()
Obtener arreglo[0] .get(posicion);
Actualizar Asigna un valor al elemento por posición. .set( posicion , elemento);
Agregar Asigna un elemento por posición. .add(elemento);
Eliminar Asigna null al elemento que se quiere eliminar. .remove(posicion);

ASOCIACIONES OPCIONALEs

CASO DE ESTUDIO: PARQUEADERO

Se quiere construir una aplicación para administrar un parqueadero (lugar de estacionamiento para carros). Dicho parqueadero tiene 40 puestos, numerados del 1 al 40.

En cada puesto se puede parquear un sólo carro (que representaremos con una clase llamada Carro), el cual se identifica por su placa. El parqueadero tiene una tarifa por hora o fracción de hora, puede ser cambiada por el administrador.

 

De cada vehículo aparcado se debe conocer la hora en la que entró, que corresponde a un valor entre 6 y 21, dado que el parqueadero está abierto entre 6 de la mañana y 9 de la noche. Se espera que la aplicación que se quiere construir permita hacer lo siguiente:

CASO DE ESTUDIO: PARQUEADERO

 

1. Ingresar un carro al parqueadero. Se debe indicar el puesto en el que se debe parquear (si hay cupo).

2. Dar salida a un carro del parqueadero. Se debe indicar cuánto debe pagar.

3. Informar los ingresos del parqueadero.

4. Consultar la cantidad de puestos disponibles.

5. Avanzar una hora en el reloj del parqueadero.

6. Cambiar la tarifa del parqueadero.

CASO DE ESTUDIO: PARQUEADERO

CLASE PARQUEADERO

public class Parqueadero
{
    //--------------------------------------------------
    // Constantes
    //--------------------------------------------------
    /** 
     * Indica el número de puestos en el parqueadero 
     */


    //--------------------------------------------------
    // Atributos
    //--------------------------------------------------
    /** 
     * Arreglo de puestos 
     */


}
public Parqueadero( )
{




}

CLASE PARQUEADERO

Escriba el constructor de la clase para inicializar las contenedoras declaradas en el punto anterior.

public int darTotalPuestosOcupados( )
{







}

CLASE PARQUEADERO

Contar y retornar el número total de puestos ocupados.

CLASE PARQUEADERO

Informar si en el parqueadero hay un carro cuya placa comience con la letra dada como parámetro.

public boolean existePlacaIniciaCon( char pLetra )
{









}

CLASE PARQUEADERO

Retornar el número de carros en el parqueadero que llegaron antes del mediodía.

public int darTotalCarrosIngresoManana( )
{








}

CLASE PARQUEADERO

Retornar el último carro en ingresar al parqueadero. Si el parqueadero está vacío, retorna null.

public Carro darCarroLlegadaMasReciente( )
{










}

CLASE PARQUEADERO

Informar si hay dos carros en el parqueadero con la misma placa.

public boolean hayPlacasRepetidas( )
{













}

¿PREGUNTAS?

¿PREGUNTAS?

Text

GRACIAS

  • J. Villalobos and R. Casallas, Fundamentos de Programación. https://cupi2.virtual.uniandes.edu.co/libro-del-curso-pdf/libro-completo
  • Iconos hechos por  Freepik, Icongeek26 de Flaticon son licenciados  por Creative Commons by 3.0
Made with Slides.com