6 de octubre de 2018

Arrays

Hasta ahora hemos estado tratando valores de manera independiente, pero es normal utilizar valores agrupados que son todos del mismo tipo: una colección de numeros, de colores, de palabras, etc...

La forma más primitiva de tratar con varios valores agrupados en un sólo valor son los arrays. La forma de declarar una variable tipo array es:
  T[] identificador; // ejemplo int[] misNumeros;
La diferencia son los corchetes, el tipo puede ser cualquiera, igual que el número de elementos a aceptar, aunque un array tiene un número de posiciones fijas que se indican a la hora de crear el array (no la variable).

Los arrays nos permiten trabajar con varios valores juntos de un mismo tipo, aunque el número de éstos es fijo


Entonces ¿Cómo le digo cuántos elementos debe contener?

Para eso vamos a tener que crear un objeto de tipo array. Para crear objetos se usa la palabra reservada new, que va a apartar memoria suficiente para contener el tipo y número de elementos (entre corchetes) que definamos. Un array se crea y asigna de esta forma:
  int[] misNumeros;
  misNumeros = new int[2];
Así tendremos en la variable misNumeros una referencia al nuevo objeto que hemos creado que será capaz de apuntar a dos valores int. También se podría declarar un tamaño cero y se conoce como un array vacío.

Si más tarde necesitáramos ampliarlo a tres, tendrémos que crear otro nuevo, pues ya el array anterior no nos serviría porque su tamaño fijo es dos.

El tamaño no tiene que ser un número fijo, puede ser cualquier expresión:
  String[] nombresAlumnos = new String[getNumeroAlumnos()];

¿Cómo accedo a las posiciones de un array?

Una vez que tengo espacio para un número de elementos, utilizaré una expresión de acceso de la forma miArray[indice], teniendo en cuenta que éstos índices deben ser del tipo int y se empiezan a contar desde cero. Estas expresiones pueden usarse como cualquier variable. Veamos un ejemplo:
  misNumeros[0] = 1;
  misNumeros[1] = misNumeros[0] + 1;
  misNumeros[2] = 3; // error en ejecución
Debemos asignar valores del tipo exacto al declarado y asegurarnos de mantener el índice dentro del tamaño, o nuestro código se romperá mientras se ejecuta.

Debo asignar valores del tipo declarado y no usar [índices] fuera del tamaño (entre 0 y n-1)


Por otra parte, si conozco los valores desde el inicio, también puedo asignarlos declarándolos en la misma asignación;
  misNumeros = new int[] { 1, 2, 3 };
Hay que tener en cuenta que cada vez que usemos new se creará un objeto nuevo aunque se asigne a la misma variable.

También se puede ver una forma más resumida (azúcar sintáctico - syntactic sugar) pero sólo si se declara la variable y se inicializa en la misma línea;
  int[] misNumeros = { 1, 2, 3 };

Arrays multidimensionales

Los de arriba son arrays de una sóla dimensión, pero pueden ser multidimensionales si seguimos añadiendo corchetes:
  • int[][]: dos dimensiones (matriz)
  • int[][][]: tres dimensiones (matriz cúbica)
Básicamente son arrays de arrays de arrays... hasta que termines de poner corchetes.

NOTA: también puede verse declarado un array como int a[]; No se suele utilizar, sólo se usa si se declaran varios arrays de distintas dimensiones en la misma línea como int[] a, b[]; siendo a de una dimensión y b de dos. Esto tratarlo como advertencia por si lo véis, pero no es normal.

Para acceder a los elementos de sus distintos niveles, se concatenarán expresiones de acceso añadiendo corchetes con los índices que hagan falta:
  int[][] miMatriz = new int[3][2];
  miMatriz[2][0] = 1; // coloca 1 en la primera posición del tercer array de arrays[2]
  System.out.println(Arrays.toString(miMatriz[2])); // imprimo el tercer array[2]
NOTA: He usado la clase java.utils.Arrays que contiene herramientas para facilitar ciertas operaciones con tipos array. Puedes ver y practicar con más métodos siguiendo su documentación.

A la hora de llamar a una posición concreta en un array multidimensional hay que tener cuidado de no exceder los límites de posiciones de cada dimensión: miMatriz[3][0] producirá un error igual que miMatriz[0][2].

Recorrer un array

Una forma típica de recorrer un array es usar un bucle for de la siguiente forma:
  for (int i = 0; i < misNumeros.length; i++) {
      System.out.println("Posición " + i + ": " + misNumeros[i]);
  }
Aquí podemos ver un miembro de los arrays que es length, que es el encargado de decirme el tamaño del array.

Para recorrer un array multidimensional usaremos los bucles for anidados que necesitemos en función de los niveles del array. Para recorrer todos los elementos de un array de dos dimensiones haremos:
  public static void imprimirMatriz(int[][] matriz) {
      for (int i = 0; i < matriz.length; i++) {
          for (int j = 0; j < matriz[0].length; j++) {
              // hacer la operación que se necesite
              System.out.print(matriz[i][j] + "\t");
              // uso \t para alinear las columnas
          }
          System.out.println(); // siguiente fila
      }
  }
Por último y el más usando si se quieren recorrer todos los elementos de una "colección", se puede usar el bucle for mejorado (enhanced for):
  for (T elemento : miArrayDeTipoT) {
      System.out.print(elemento);
  }
Con los arrays podemos usar el bucle for mejorado


Pero ojo, los arrays sólo apuntan a valores, no los guardan

Podemos entender que los arrays son almacenes de datos, pero en realidad son un conjunto de variables pero que en vez de tener un identificador usan expresiones de acceso como se explicó antes.

Con los tipos por referencia no se harán copias aunque ocupen posiciones distintas del array.

Vamos a hacer un par de arrays que usaré para rellenar un array de arrays. Uno de ellos lo voy a poner dos veces y veremos que si se modifica cualquiera de los arrays, el cambio se produce en ellos, no en el array de arrays. Se ve más fácil en el vídeo:
  int[] a = {1 , 2};
  int[] b = {3 , 4};     
  int[][] aba = { a , b, a };
  imprimirMatriz(aba);
  System.out.println();
  // cambiamos el primer valor
  aba[0][0] = 5;
  imprimirMatriz(aba);
  // pero lo que cambia es "a"
  // no entender como una copia
  // es el mismo objeto
  // se ve en esta impresion
  System.out.println(Arrays.toString(aba));
  System.out.println("a es: " + Arrays.toString(a));
  System.out.println();

  // cambiamos el tercer array
  aba[2] = new int[] { 6, 7 };
  imprimirMatriz(aba);
  // ahora son 3 objetos distintos
  System.out.println(Arrays.toString(aba));
Tenemos la siguiente salida, aunque los números que identifican los objetos serán distintos para cada uno.

1      2 
3      4 
1      2 

5      2 
3      4 
5      2 
[[I@52e922, [I@25154f, [I@52e922]
a es: [5, 2]

5      2 
3      4 
6      7 
[[I@52e922, [I@25154f, [I@10dea4e]
NOTA (nivel avanzado): Esas cadenas de caracteres trípticos que hemos obtenido vienen del método getName() de la clase Class y nos dicen de qué tipo es el objeto (en nuestro caso array de int). Puedes leer más en la API de java.

He marcado en rojo los objetos repetidos.

Con los arrays hacemos referencia al tipo declarado, no se hacen copias de valores al asignarlos

5 comentarios:

  1. El código donde se explica el for mejorado, creo que está equivocado. Lo correcto debería ser:

    for (T elemento : miArrayDeTipoT) {
    System.out.print(elemento);
    }

    ResponderEliminar
    Respuestas
    1. Cierto, primero le puse de identificador "t" y sólo cambié a "elemento" en un sitio. Lo actualizo ¡Bien visto!

      Eliminar
  2. Para declarar un Array, Creo que hay muchas maneras

    int MisNumeros[] = new int[4];

    O
    int[] MisNumeros = new int[4];

    O
    int MisNumeros[];
    MisNumeros = new int[4];

    O

    int[] MisNumeros;
    MisNumeros = new int[4];

    ResponderEliminar
    Respuestas
    1. En realidad para declarar hay 2:
      int[] misNumeros;
      int misNumerosOtraManera[];

      Las dos últimas formas simplemente es repetir las dos anteriores pero separando la declaración de la asignación. Es lo que comento en la nota que lleva al enlace de la documentación de Oracle:
      https://docs.oracle.com/javase/specs/jls/se8/html/jls-10.html#jls-10.2

      Eliminar
    2. Eso es,
      Puse este comentario porque creo que esta declaración es la más cercana a la declaración algorítmica.

      Eliminar

Compárteme

Entradas populares