05.Arrays

Arrays

Arrays Unidimensionales

Introducción

Vamos a ver la primera estructura de datos del curso. Como estructura definiremos como una colección de objetos, que se agrupan o se almacenan juntos. Los arrays tienen varios nombres que podéis encontraros: vector y arreglo. Estos objetos o elementos que se agrupan tienen un índice o clave para poder acceder a ellos. Y estos objetos deben ser del mismo tipo (Clases o tipos primitivos). La forma de un array unidimensional es la de un String que habéis estado utilizando hasta ahora, pero ahora no sólo podemos guardar unos caractéres juntos sino todo tipo de objetos. Intro

Un array puede tener más de una dimensión, pero esto lo veremos más adelante. Lo que hay que tener claro que cada elemento del array es referenciado por la posición que ocupa dentro del índice. Es una indexación directa, y no hay necesidad de recorrer toda la estructura de datos. Importante: la primera posición del array es la 0.

Otro aspecto muy relavante es que los arrays son estructuras de datos estáticas, es decir debemos reservar el tamaño máximo del array (número de elementos que podemos almacenar o referenciar). Esta tamaño no podrá ser modificado, más adelante veremos estructuras de datos dinámicas.

Declaración

En la declaración de un array debemos indicar que tipo de objetos queremos almacenar en el, y se usar los corchetes: tipo [] nombre;

int []  id_productos;
String [] nombres;
Cliente [] listadosCliente;

Este paso sólamente crear la variable que va a referenciar un array.

Inicialización

Una vez que tenemos la “variable array”, tenemos que crear el array y se reserva la memoria para el. En este paso hay que indicar el tamaño que va a tener: nombre = new tipo [tamaño];

id_productos = new int [10]; // acabamos de crear un array de 10 números enteros
nombre = new String [5];

Por supuesto la declaración y la inicialización lo podéis hacer en una misma línea, pero es interesante diferenciar las dos fases:

Cliente [] listadoClientes = new Cliente [20]; // hemos creado un array unidimensional para 20 objetos cliente
float [] temp_maxs = new float [10];

Ojo!: al crear el array no creamos los objetos que van a ir dentro del array, sólo reservamos memoria para las referencias de ellos.

  • Para tipos numéricos -> 0
  • Para tipo boolean -> false
  • Para objetos -> null

Inicialización + Declaración + Creación

Java nos permite al crear un array inicializar con valores en el momento de la declaración. Esta es la forma: Ini

De esta forma no es necesario indicarle Java el tamaño del array. Ya se reserva y sea crea las posiciones necesarias en base a los valores indicados. Ejemplo:

String [] dias_semana = {"Lunes", "Martes", "Miércoles", "Viernes"};

Lectura y escritura de los elementos

Para la lectura como para asignar un valor/objeto a una posición de un array es necesario un índice que representará la posición, se usa los corchetes para ello:

dias_semana[2] = "Sabado"; // escritura
System.out.println(dias_semana[3]); //lectura

Para no cometer errores de acceso o de escritura debes siempre saber que el índice empieza en 0 y que la máxima posición de un array viene determinada por la propiedad length:

int [] lista = new int[10];
System.out.println (lista.length);

En caso de acceder a una posición del array que no existe se producirá la excepción ArrayIndexOutOfBoundsException en tiempo de ejecución.

Acceso y recorrer (bucle for-each)

Ya sabemos acceder a través de un índice a una posición concreta de un array, pero a veces necesitamos recorrer el array por completo de principio a fin.

  • Usando un for normal controlando los indices:
int [] numbers = {5, 3, 9, 2, 8};
for (int i=0; i<numbers.length; i++){
    System.out.println(numbers[i]);
}
  • Usando el for-each:
for (int n : numbers){
    System.out.println(n);
}

Fíjate bien cómo está construido este for porque ahí está la clave: int n : numbers. La variable numbers es el array y la variable n es un entero que toma el valor de un elemento del array en cada iteración. En este caso el array es de tipo int, por eso la variable n también lo es. Si el array almacenase datos de tipo float esta variable también tendría que ser de ese tipo. Siempre debe coincidir el tipo de esta variable con el tipo del array. Es un “for” más automático y cómodo de usar, pero no nos permite hacer saltos, o iteraciones diferentes -> siempre es del inicio al final salvo que uséis break o continue.

  • También podemos usar while, pero lógicamente debemos controlar el índice:
int [] numbers = {5, 3, 9, 2, 8};      
int i=0;
while (i<numbers.length){
    System.out.println(numbers[i]);
    i++;
}

Ejercicio 1

Crea un programa que cuente cuántos números pares e impares hay en un array.

Ejercicio 2

Eliminar duplicados: Crea un programa que elimine los elementos duplicados de un array. Ese array estará compuesto de números enteros. Para facilitar la tarea ordénado lo previamente.

Prueba una función estática de la clase Arrays (ya indagaremos en ellas): Arrays.sort(int [] a)

Una vez tengas “limpiado” el array puedes crear uno nuevo con el tamaño correcto con: Arrays.copyOf(array, indice)

Referencias

Cómo ya sabemos, los arrays son objetos y sus variables, contienen unicamente referencias a dichos objetos en memoria. Entonces si asignáis una variable array a otro no estamos copiando un array, estan ambas variables apuntando al mismo array. Ejemplo:

int[] ar1 = {3,7,8,9};
int[] ar2 = ar1;
ar2 [2] = 99;
for ( int i : ar1){ Syste.out.println(i);}

Ejercicio 3

Desarrolla una pequeña aplicación de agenda con unos contactos. La información de los contactos será: nombre, apellido, email y teléfono Se crean varios contactos de ejemplo internamente. Tendremos un máximo de 20 contactos, y las funcionalidades a implementar son las siguientes:

  • Mostrar todos los contactos por pantalla.
  • Búsqueda de contacto por email y actualizarlo (entrada de datos por teclado).
  • Validación del email: que tenga sólo una ‘@’

Método varargs

Un método varargs es aquel que recibe un número variable de argumentos. Fue introducido en Java 5 y es aplicable también a constructores. Es conocido también como método de argumentos variables. Se caracteriza por utilizar 3 puntos o puntos suspensivos en la declaración de los argumentos. Sintásis -> tipo de datos … nombre argumento Estos argumentos variables son un array unidimensional normal que podemos recorrer. Y el tipo de elementos del array es el tipo a la izquierda de tres puntos suspensivos:

public static int max(int... valores){
        int max = Integer.MIN_VALUE;
        for(int valor : valores) {
            if(valor > max)
                max = valor;
        }        
        return max;        
    }

Restriciones para varargs:

  • No puede haber más de 1 vargar en la cabecera del método.
  • Si hay otros argumentos en la cabecera, el varargs debe colocarse al final:
public static int max(int... valores, String msg) // ERROR
public static int max(String msg, int...valores) // CORRECTO
  • Si hay sobrecarga de metodos con varargs, Java siempre priorizará el método con los parámetros más exactos. Compruébalo!

Paso de argumentos por consola/terminal

Introducción

Vamos a ver otra forma (ya menos usada en la actualidad) de mandar datos a nuestro programa desde la ejecución de un programa. Siempre serán datos de entrada. Hoy dos alternativas, por terminal o por el IDE.

Mandar datos a traves de terminal

Para ello al ejecutar un programa en Java, con el nombre de la clase sin la extensión y a continuación los parámetro/s de entrada con espacios:

javac MyCompute.java
java MyCompute 4

Logicamente antes hay que compilar. Y en el ejemplo anterior a nuestro programa MyCompute le mandaríamos un “4”.

Usando un IDE

Usando un entorno de desarrollo como Eclipse hay que acceder sobre una clase que tenga main, “Run As”, “Run Configurations”, pestaña “Arguments”, introducimos los parámetros en “Program arguments” y ejecutamos:

IDE Eclipse

Tener cuidado en “Run Configurations” en elegir el proyecto y la clase correcta.

¿Cómo se recogen los datos de entrada?

En la cabecera del método main tenemos un arrays de Strings que se llama por defecto args:

public class HelloCommandLineArguments {
   
    public static void main( String[] args ){
       
        // Check if a command line argument exists
        if(args.length == 0)
            System.exit(0);
           
        // Display the arguments from the command line
        for(int counter = 0; counter < args.length; counter++){
            System.out.println("argument index " + counter + ": " + args[counter]);  
        }
    }

}

En el anterior ejemplo podemos comprobar si el programa recibe datos de entrada (si no hay termina) y en caso afirmativo mostrarlos por pantalla. Siempre recibiremos datos en String y se comportará args como un array unidimesional normal.

Novedad con varargs

Lo hemos visto con arrays unidimensionales en el anterior punto, nos podemos encontrar con un main de esta forma:

public class SimpleTesting {
  public static void main(String... args) {
    String val1 = args[0];
    String val2 = args[1];
    System.out.println(val1);
    System.out.println(val2);
  }
}
}

Fuente: enlace

Arrays Multidimensionales

Introdución

Estos arrays tienen la característica de tener más de una dimensión, es decir tendrán más de un índice para poder acceder a una posición del mismo. El ejemplo más sencillo será el de dos dimensiones y la forma conceptual sería el de una tabla con columnas y filas. Para Java no es más que un array de arrays. Multi

Declaración

La declaración es igual que con los arrays unidimensionales, pero con más par de corchetes “[]”, un par por cada dimensión:

tipo [][]…[] nombre_array = new tipo [cap1][cap2]…[capn];

Para crear un array de dos dimensiones de dos filas y tres columnas de “doubles”:

double [][] tabla = new double [2][3];

El acceso a una posición a partir de los dos indices: Multi2

Acceso y modificación o escritura

int[][] myNumbers = { {1, 2, 3, 4}, {5, 6, 7} };
System.out.println(myNumbers[1][2]); // Outputs 7
myNumbers[1][2] = 9;
System.out.println(myNumbers[1][2]);

Inicialización

También podemos inicializar con valores en la declaración de un array multidimensional, se usarán las llaves “{}” para agrupar los elementos de cada dimensión, y cada dimensión separado por “,”. Ejemplo:

double [][] tabla = {
    {3.6, 8.2, 12,1},
    {4.0, 23.4, 11}
};

Extra: podemos crear array irregulares y sólo tendremos que declarar el tamaño de la primera dimensión -> enlace.

Recorrer

Para recorrer array de más de una dimensión siempre habrá que programar un bucle por cada dimensión, y normalmente anidados. Se suelen utilizar for o for-each:

int[][] matriz={{1,2,3},{4,5},{6,7,8,9,10},{11}};
for(int i=0;i<matriz.length;i++){
    for(int j=0;j<matriz[i].length;j++){
        System.out.print(matriz[i][j]);
    }
}

Ejemplo de array de 3 dimensiones:

public class Array3DimensionesAleatorio {
     
    private static Scanner entrada;
 
    public static void main(String[] args) {
        System.out.print("\n");
        int array3D[][][];
        int x = pedirNumeroEntero("Introduce la primera dimensión: ");
        int y = pedirNumeroEntero("Introduce la segunda dimensión: ");
        int z = pedirNumeroEntero("Introduce la tercera dimensión: ");
        array3D = new int[x][y][z];
        inicializarArray3D(array3D);
        visualizar(array3D);
    }
     
    static void inicializarArray3D(int[][][] pArray){
        Random r = new Random();
        for(int i=0;i<pArray.length;i++){
            for(int j=0;j<pArray[i].length;j++){
                for(int k=0;k<pArray[i][j].length;k++){
                    pArray[i][j][k] = r.nextInt(11);
                }
            }
        }
    }
     
    static void visualizar(int[][][] pArray){
        int numElementos = 0, sumaElementos = 0;
        for(int i=0;i<pArray.length;i++){
            for(int j=0;j<pArray[i].length;j++){
                for(int k=0;k<pArray[i][j].length;k++){
                    System.out.print("\t" + pArray[i][j][k]);
                    numElementos++;
                    sumaElementos += pArray[i][j][k];
                }
                System.out.print("\n");
            }
            System.out.print("\n\n");
        }
        System.out.printf("La media de los elementos es %.2f", (double)sumaElementos/numElementos);
    }
     
    static int pedirNumeroEntero(String s){
        int num;
        entrada = new Scanner(System.in);
        do {
            System.out.print(s);
            num = entrada.nextInt();
            if(num<=0){
                System.out.println("La dimensión de la matriz debe ser mayor que 0.\n");
            }
        } while (num<=0);
        return num;
    }
}

Clase Arrays

La API de Java incluye la clase java.util.Arrays que ofrece una funcionalidades muy prácticas con sus métodos estáticos. Estos son los más importantes:

  • static String toString ( tipo[] array): imprime los elementos del array.
  • static void fill (tipo[] array, tipo valor): inicializa el array con el valor que se le pasa.
  • static boolean equals (tipo[] array, tipo[] arrayb): compara uno a uno los elementos de los dos arrays.
  • static void sort (tipo[] array): ordena ascendentemente el array.
  • static tipo[] copyOf (tipo[] array, int len): devuelve un nuevo array de len elementos inicializados con los valores de array.
  • hay muchos más descúbrelos!

Ejercicio 1

class Unidad4 {

  public static void main(String args[]){

      int[][] arrayDosD= new int[3][];

      arrayDosD[0]=new int[4];

      arrayDosD[1]=new int[2];

      arrayDosD[2]=new int[3];

      System.out.println("cargamos e imprimimos arrayDosD[0]. Observa que su  tamaño es 4");

      for(int j=0;j<4;j++){   //utilizamos la variable j pero podría ser i, z, ....

        arrayDosD[0][j]=0*j + 0 + j*2; //cargamos la matriz

        System.out.println("arrayDosD[0]["+ j +"]="+ arrayDosD[0][j]);

      }

 

      System.out.println("\ncargamos e imprimimos arrayDosD[1]. Observa que su  tamaño es 2");

      for(int j=0;j<2;j++){

        arrayDosD[1][j]=1*j + 1 + j*2; //cargamos la matriz

        System.out.println("arrayDosD[1]["+ j +"]="+ arrayDosD[1][j]);

      }

 

      System.out.println("\ncargamos e imprimimos arrayDosD[2]. Observa que su  tamaño es 3");

      //para ahondar en el concepto de referencia a array hago la ultima impresión con paso intermedio

      int[] x=arrayDosD[2];

      for(int j=0;j<3;j++){

        x[j]=2*j + 2 + j*2; //cargamos la matriz

        System.out.println("arrayDosD[2]["+ j +"]="+ x[j]);

      }}}

Volver a escribir el ejemplo anterior utilizando el atributo length, lo que permite utilizar de nuevo un bucle anidado en otro y hacer un código más compacto.

Ejercicio 2

int[][] matriz ={{0,2,4},{1,3,5}};

Inicializa arrayDosD con la sintaxis anterior e imprime su contenido según el siguiente gráfico: Ejercicio 2

Ejercicio 3

Si no lo hiciste ya, vuelve a escribir el ejercicio anterior de forma que utilice el “for mejorado”. Puedes simplificar la impresión a algo del estilo de

11 12 13 14

21 22

31 32 33

Ejercicio 4

Con una matriz cuadrada, introduciendo el tamaño por argumento, inicializar aleatoriamente la matriz y luego modificarla intercambiando la diagonal principal con la secundaria. Ejemplo:

Ejercicio 3

Ejercicio 5

Con una matriz cuadrada, introduciendo el tamaño por argumento, inicializar aleatoriamente la matriz y luego modificarla invirtiendo los valores de la diagonal principal entre ellos, y los de la diagonal secundaria entre ellos:

Ejercicio 2

Ejercicio 6

Como caso concreto del cuadro anterior, se pide que simules un conteo con 3 dimensiones: hora, dia y mes. Llena aleatoriamente el array y se pide:

  • Que imprimas mes a mes los valores de la matriz
  • Que muestres de cada mes el día con más coches
  • Y al final, que muestres del 3 marzo la hora que registra el mayor conteo

Para simplificar, desprecia años bisiesto y febrero siempre tiene 28 días. Para inicializar el array supon conteo entre 0 y 999